Elegoo car project advice

A few other students and I are working on a project for class, where we essentially are using the elegoo car to paint a scenario for other uses it may have in the future. We decided on the idea for a lawn mower bot that could potentially help disabled people with lawn care. It more or less is just supposed to be a proof of concept, but we have started to struggle with the code. We have decent line tracking, but in one of out scenarios, we want to show what the bot will do when confronted with an obstacle. The idea is to have it do either a half circle or square-like maneuver around the object(whichever is easier to code). However, the bot is initially following a line, but must leave the line to perform the maneuver and then continue past the object. Is there any advice or suggestions that you all think would make this possible?

Thanks

I don't know of any lawn mowers that follow lines (at least not visible lines) but if you were going for a "Real World" proof of concept, then you would define a work area by either markers or GPS coordinates.

What are you using to detect objects? I'm guessing a ping sensor similar to the HC-SR04? If so, are you using a single sensor or an array of sensors?

Can you post what you have now this way we can see how far along you are? Please include schematic and a parts list if possible.

sorry, I should have been more specific. We are using the Elegoo car kit v3 which looks something like this

and this is my current code used for line tracking

// Pin assignments
#define MIDDLE_SENSOR A1
#define RIGHT_SENSOR  A2

#define ENA 5    // Left motor speed
#define ENB 6    // Right motor speed
#define IN1 7    // Left motor direction
#define IN2 8
#define IN3 9    // Right motor direction
#define IN4 11

void setup() {
  pinMode(LEFT_SENSOR, INPUT);
  pinMode(MIDDLE_SENSOR, INPUT);
  pinMode(RIGHT_SENSOR, INPUT);

  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
}

void loop() {
  int left = digitalRead(LEFT_SENSOR);
  int middle = digitalRead(MIDDLE_SENSOR);
  int right = digitalRead(RIGHT_SENSOR);

  // Line detected = LOW, White surface = HIGH
  if (middle == LOW && left == HIGH && right == HIGH) {
    // Go straight
    goForward();
  }
  else if (left == LOW) {
    // Turn left
    turnLeft();
  }
  else if (right == LOW) {
    // Turn right
    turnRight();
  }
  else {
    // Stop or lost line
    stopCar();
  }
}

void goForward() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 150); // Adjust speed as needed
  analogWrite(ENB, 150);
}

void turnLeft() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 100);
  analogWrite(ENB, 150);
}

void turnRight() {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
  analogWrite(ENA, 150);
  analogWrite(ENB, 100);
}

void stopCar() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
}

this is more of a smaller project to show off the versatility of the bot

sorry I have sent the wrong code. Here is the correct code for line tracking

//Line Tracking IO define
#define LT_R !digitalRead(10)
#define LT_M !digitalRead(4)
#define LT_L !digitalRead(2)

#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11

#define carSpeed 100

void forward(){
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
}

void back(){
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
}

void left(){
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
}

void right(){
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
}

void stop(){
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}

void setup(){
Serial.begin(9600);
pinMode(LT_R,INPUT);
pinMode(LT_M,INPUT);
pinMode(LT_L,INPUT);
}

void loop() {
if(LT_M){
forward();
}
else if(LT_R) {
right();
while(LT_R);
}
else if(LT_L) {
left();
while(LT_L);
}
}

Who puts the lines down? You are burdening your target customer to do twice the work for the same result.

The lines are more of a visible representation of how the bot would move in a different setting. In real life, the lines would probably be predetermined to minimize the need for extra input. I am open to criticism.

Your code has no obstacle detection. You also need a means to measure bearing and travel distance.

Okay here is our new code, we added an led to blink at the end foe the scenario that its stuck.

#include <Servo.h>

// Line Tracking IO define
#define LT_R !digitalRead(10)
#define LT_M !digitalRead(4)
#define LT_L !digitalRead(2)

#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11
#define carSpeed 148

Servo myServo;
int Echo = A4;
int Trig = A5;
int LEDPin = 13;
int rightDistance = 0;
int leftDistance = 0;
int middleDistance = 0;

// Function to measure distance
int Distance_test() {
digitalWrite(Trig, LOW);
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(20);
digitalWrite(Trig, LOW);
float Fdistance = pulseIn(Echo, HIGH);
return (int)(Fdistance / 58);
}

// LED Blinking Function
void BlinkLED() {
for (int i = 0; i < 5; i++) {
digitalWrite(LEDPin, HIGH);
delay(200);
digitalWrite(LEDPin, LOW);
delay(200);
}
}

// Movement Functions
void forward2() {
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
}

void back2() {
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
}

void left2() {
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
}

void right2() {
analogWrite(ENA, carSpeed);
analogWrite(ENB, carSpeed);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
}

void stop2() {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
}

// Setup function
void setup() {
Serial.begin(9600);
myServo.attach(3);

pinMode(Echo, INPUT);
pinMode(Trig, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(LEDPin, OUTPUT);
pinMode(10, INPUT); // LT_R
pinMode(4, INPUT); // LT_M
pinMode(2, INPUT); // LT_L
}

// Loop function
void loop() {
myServo.write(90);
delay(300);
middleDistance = Distance_test();
delay(300);

if (LT_M) {
forward2();
} else if (LT_R) {
right2();
while (LT_R);
} else if (LT_L) {
left2();
while (LT_L);
}

if (middleDistance <= 35) {
stop2();
myServo.write(0);
delay(300);
rightDistance = Distance_test();
delay(300);
myServo.write(180);
delay(300);
leftDistance = Distance_test();
delay(300);
myServo.write(90);

if (rightDistance > leftDistance) {
right2();
delay(500);
} else if (leftDistance > rightDistance) {
left2();
delay(500);
} else if ((rightDistance <= 40) && (leftDistance <= 40)) { // If both sides are blocked
stop2();
BlinkLED();
delay(1000);
} else {
forward2();
}
}
}

The delay() functions are not letting your sensors or motors work as they should.
The middle button seems unresponsive.
You use magic numbers. Replace them with descriptive variables.
You need debug (print) statements to show what is happening.

I realize this is not an answer to the original post but I agree about the delays. Get rid of the delays. You have delays inside delays. They add up. If you want any consistent responsiveness, learn how to time events with the millis().

EVERY time I use to have a simple code but something would not work consistently, it was the delays. I learned how to code my timing with the millis() and haven't looked back. It is very difficult to work through problems when the problems are inconsistent.

Now when I have a problem to figure out, at least I can rule out the timing. (Usually...)

And for what it's worth, comment out tons of notes also. Next week you might not remember why you coded it that particular way last week. It also helps people looking at it help you. They might be able to better understand your goals.

1 Like

Your program is "linear," meaning, one event/device completes before another event/device starts. This becomes "blocking" to sensors and motors, as every device must wait for all the other devices to complete before beginning with the first device again.

Are you aware of a timing mechanism using millis() which allows you to schedule events non-linearly by giving each device a slice of time to complete a slice of their task. In the Arduino world, this seems to be called "multi-tasking" (but it is not).

Your project needs to (1) line sense, (2) object detect, (3) move a servo, (4) move motors, but they all do not need the same amount of time to complete their task. The line sensing might need to happen every 100ms. The object detection might only need to happen every 500ms. The servo movement only happens after object detection, and motor drive happens continuously, reacting to line sensing and object detection, and probably to move toward a destination.

Find material on "millis() multiple events" to help manage MCU time for your devices.

diagram.json for wokwi
{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": 0, "left": 0, "attrs": {} },
    {
      "type": "wokwi-pushbutton",
      "id": "btn1",
      "top": -22.6,
      "left": -86.4,
      "attrs": { "color": "green", "xray": "1" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -116.4,
      "left": 93,
      "rotate": 90,
      "attrs": { "color": "green" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": -97.2,
      "left": 93,
      "rotate": 90,
      "attrs": { "color": "white" }
    },
    {
      "type": "wokwi-led",
      "id": "led3",
      "top": -78,
      "left": 93,
      "rotate": 90,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led4",
      "top": -116.4,
      "left": 20.6,
      "rotate": 270,
      "attrs": { "color": "green", "flip": "1" }
    },
    {
      "type": "wokwi-led",
      "id": "led5",
      "top": -97.2,
      "left": 20.6,
      "rotate": 270,
      "attrs": { "color": "white", "flip": "1" }
    },
    {
      "type": "wokwi-led",
      "id": "led6",
      "top": -78,
      "left": 20.6,
      "rotate": 270,
      "attrs": { "color": "red", "flip": "1" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn2",
      "top": -70.6,
      "left": -86.4,
      "attrs": { "color": "green", "xray": "1" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn3",
      "top": -118.6,
      "left": -86.4,
      "attrs": { "color": "green", "xray": "1" }
    },
    {
      "type": "wokwi-hc-sr04",
      "id": "ultrasonic1",
      "top": -84.9,
      "left": 139.9,
      "attrs": { "distance": "148" }
    },
    { "type": "wokwi-servo", "id": "servo1", "top": -184.4, "left": 144, "attrs": {} }
  ],
  "connections": [
    [ "nano:GND.2", "led3:C", "black", [ "v-43.2", "h-38.9", "v-19.2" ] ],
    [ "led3:C", "led2:C", "green", [ "h-9.6", "v-18.8" ] ],
    [ "led2:C", "led1:C", "green", [ "h-9.6", "v-18.8" ] ],
    [ "led1:C", "led4:C", "green", [ "h0" ] ],
    [ "led4:C", "led5:C", "green", [ "h9.6", "v0.4" ] ],
    [ "led5:C", "led6:C", "green", [ "h9.6", "v19.6" ] ],
    [ "nano:5", "led5:A", "green", [ "v-33.6", "h-10.1", "v-38.4" ] ],
    [ "nano:6", "led2:A", "green", [ "v-72", "h-0.5" ] ],
    [ "nano:7", "led4:A", "green", [ "v-33.6", "h9.1", "v-57.6" ] ],
    [ "nano:8", "led6:A", "green", [ "v-33.6", "h18.7", "v-19.2" ] ],
    [ "nano:GND.2", "btn2:2.r", "black", [ "v0" ] ],
    [ "btn2:2.r", "btn1:2.r", "green", [ "h9.8", "v19.4" ] ],
    [ "btn2:2.r", "btn3:2.r", "green", [ "h9.8", "v-47.8" ] ],
    [ "nano:10", "btn3:1.r", "green", [ "v-33.6", "h-38.9", "v-76.8" ] ],
    [ "nano:3", "btn2:1.r", "green", [ "v-33.6", "h-106.1", "v-28.8" ] ],
    [ "nano:2", "btn1:1.r", "green", [ "v-33.6", "h-115.7", "v19.2" ] ],
    [ "ultrasonic1:VCC", "nano:5V.2", "red", [ "v0" ] ],
    [ "ultrasonic1:TRIG", "nano:A5", "green", [ "v67.2", "h-125.2" ] ],
    [ "ultrasonic1:ECHO", "nano:A4", "green", [ "v76.8", "h-154.4" ] ],
    [ "ultrasonic1:GND", "nano:GND.3", "black", [ "v0" ] ],
    [ "nano:9", "led3:A", "green", [ "v-33.6", "h28.3", "v-19.2" ] ],
    [ "nano:11", "led1:A", "green", [ "v-33.6", "h47.5", "v-57.6" ] ],
    [ "nano:4", "servo1:PWM", "green", [ "v-33.6", "h37.9", "v-76.8" ] ],
    [ "nano:GND.3", "servo1:GND", "black", [ "v-4.8", "h-19.7", "v-153.6" ] ],
    [ "nano:5V.2", "servo1:V+", "red", [ "v4.8", "h-19.7", "v-163.2" ] ]
  ],
  "dependencies": {}
}

Yes for your project you need to get the timing sorted out. The problem with delay is that the program gets "stuck" at that spot of code for that allotted delay time.

If you have 1 second of delays in your loop, that is more than enough time to mow over Mrs. Johnson's water hose because you enabled the drive motors and blades but could not disable them or steer the machine when an object was sensed due to your delays blocking the rest of your code. The sensor will be prevented from sensing and your mower will just keep on going because that is the last command you gave it.

I think in at least one of your functions you have a delay. You call the function and then have a delay in the loop very quickly after that. These all add up.

I may not be a pro at coding and electronics (FAR from it. I am a welder that found a fun hobby), but I’ve learned that when working on anything beyond simply flashing an LED, using millis() for timing is the way to go.

Get your timing sorted out. Then start your code with one motor control. Get that working. Then add another motor and get that working. Then add a sensor and get that working. Etc, etc, etc...

Serial prints help to find problems. Even with wiring issues because you can read the real results in real time. I found out, not too long ago, that I had a bad button. The multimeter confirmed it. These serial prints can be printed with the millis() as well.

I was always eager to code it all at once. But having a large code will make it difficult to pinpoint issues. Coding it one step at a time will uncover those problems as they arise. And as a bonus, if you are a fan of copy/paste, you don't paste the same error all over your program.

I mentioned delay() should be replaced by a timing mechanism called millis()... here is an example that you can test that reads your sensor pins every second (and works with the wokwi diagram.json in post #11). Descriptive comments are in the code. It should give you a look into timing. The next thing you should do is write a timing scheme... how often should the HCSR04 pin, what what to do with an "object" return, how often to read the line sensors, how often to move the motor. Ask any question.

byte lineSensorPin[] = {10, 4, 2}; // left, middle, right line sensor
byte sensorArraySize = sizeof(lineSensorPin) / sizeof(lineSensorPin[0]);
unsigned long timer, timeout = 1000; // in milliseconds

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < sensorArraySize; i++)
    pinMode(lineSensorPin[i], INPUT_PULLUP); // nominal HIGH, active LOW
}

void loop() {
  // "millis()" is "NOW" time
  // "timer" holds "last" time
  // "timeout" is duration between events

  if (millis() - timer > timeout) { // compare difference of NOW and "last" against duration
    timer = millis(); // store new "last" time
    readSensors(); // call the event function
  }
}

void readSensors() {
  for (int i = 0; i < sensorArraySize; i++) { // count through the pins
    Serial.print("(S"); // label the reading
    Serial.print(i); // element of pin number array
    Serial.print(":"); // a separator
    Serial.print(digitalRead(lineSensorPin[i])); // the value of the pin
    Serial.print(") "); // more formatting
  }
  Serial.println(); // separate readings
}

I take back the need to remove all calls to delay() ... Your sketch used them to allow the servo or the motors to physically move to a position. Here is an update to your sketch that prints out (rather cryptically) turn direction, active line sensor and more. I hope it works.

#include <Servo.h>
#define servoPin 4
Servo myServo;
byte servoHome = 90, servoLeft = 30, servoRight = 150;

// Line Tracking IO define
#define LTL 2
#define LTM 4
#define LTR 10
#define LT_R !digitalRead(LTR)
#define LT_M !digitalRead(LTM)
#define LT_L !digitalRead(LTL)

// motors
#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11
#define CARSPEED 127

// SR04
int Echo = A4;
int Trig = A5;
int LEDPin = 13;
int rightDistance = 0;
int leftDistance = 0;
int middleDistance = 0;
int stopDistance = 35;

// Function to measure distance
int Distance_test() {
  digitalWrite(Trig, LOW);
  delayMicroseconds(2);
  digitalWrite(Trig, HIGH);
  delayMicroseconds(20);
  digitalWrite(Trig, LOW);
  float Fdistance = pulseIn(Echo, HIGH);
  return (int)(Fdistance / 58);
}

// LED Blinking Function
void BlinkLED() {
  for (int i = 0; i < 5; i++) {
    digitalWrite(LEDPin, HIGH);
    delay(200);
    digitalWrite(LEDPin, LOW);
    delay(200);
  }
}

// Movement Functions
void move(int in1, int in2, int in3, int in4, char dir) {
  Serial.print(dir);
  analogWrite(ENA, CARSPEED);
  analogWrite(ENB, CARSPEED);
  digitalWrite(IN1, in1);
  digitalWrite(IN2, in2);
  digitalWrite(IN3, in3);
  digitalWrite(IN4, in4);
}

void forward2() {
  move(HIGH, LOW, LOW, HIGH, 'F');
}

void back2() {
  move(LOW, HIGH, HIGH, LOW, 'B');
}

void left2() {
  move(LOW, HIGH, LOW, HIGH, 'L');
}

void right2() {
  move(HIGH, LOW, HIGH, LOW, 'R');
}

void stop2() {
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
  move(LOW, LOW, LOW, LOW, 'S');
}

// Setup function
void setup() {
  Serial.begin(115200);
  myServo.attach(servoPin);

  pinMode(Echo, INPUT);
  pinMode(Trig, OUTPUT);

  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);

  pinMode(LEDPin, OUTPUT);

  pinMode(LTR, INPUT); // LT_R
  pinMode(LTM, INPUT); // LT_M
  pinMode(LTL, INPUT); // LT_L

  stop2(); // begin in "stop" position
}

void loop() {
  myServo.write(servoHome); // forward

  if (Distance_test() <= stopDistance) {
    stop2();

    myServo.write(servoRight);
    delay(300);
    rightDistance = Distance_test();
    myServo.write(servoLeft);
    delay(300);
    leftDistance = Distance_test();
    myServo.write(servoHome);

    if (rightDistance > leftDistance) {
      Serial.print("DR");
      Serial.print(rightDistance);
      right2();
      delay(500);
    } else if (leftDistance > rightDistance) {
      Serial.print("DL");
      Serial.print(leftDistance);
      left2();
      delay(500);
    } else if ((rightDistance <= 40) && (leftDistance <= 40)) { // If both sides are blocked
      Serial.print(" BLOCKED");
      stop2();
      BlinkLED();
      delay(1000);
    } else {
      forward2();
    }
  }

  if (LT_M) {
    Serial.print(" LM ");
    forward2();
  } else if (LT_R) {
    Serial.print(" LR ");
    right2();
    while (LT_R);
  } else if (LT_L) {
    Serial.print(" LL ");
    left2();
    while (LT_L);
  }
}
diagrm.json for wokwi
{
  "version": 1,
  "author": "Anonymous maker",
  "editor": "wokwi",
  "parts": [
    { "type": "wokwi-arduino-nano", "id": "nano", "top": 4.8, "left": -0.5, "attrs": {} },
    {
      "type": "wokwi-pushbutton",
      "id": "btn1",
      "top": -22.6,
      "left": -86.4,
      "attrs": { "color": "green", "xray": "1" }
    },
    {
      "type": "wokwi-led",
      "id": "led1",
      "top": -116.4,
      "left": 93,
      "rotate": 90,
      "attrs": { "color": "green" }
    },
    {
      "type": "wokwi-led",
      "id": "led2",
      "top": -97.2,
      "left": 93,
      "rotate": 90,
      "attrs": { "color": "white" }
    },
    {
      "type": "wokwi-led",
      "id": "led3",
      "top": -78,
      "left": 93,
      "rotate": 90,
      "attrs": { "color": "red" }
    },
    {
      "type": "wokwi-led",
      "id": "led4",
      "top": -116.4,
      "left": 20.6,
      "rotate": 270,
      "attrs": { "color": "green", "flip": "1" }
    },
    {
      "type": "wokwi-led",
      "id": "led5",
      "top": -97.2,
      "left": 20.6,
      "rotate": 270,
      "attrs": { "color": "white", "flip": "1" }
    },
    {
      "type": "wokwi-led",
      "id": "led6",
      "top": -78,
      "left": 20.6,
      "rotate": 270,
      "attrs": { "color": "red", "flip": "1" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn2",
      "top": -70.6,
      "left": -86.4,
      "attrs": { "color": "blue", "xray": "1" }
    },
    {
      "type": "wokwi-pushbutton",
      "id": "btn3",
      "top": -118.6,
      "left": -86.4,
      "attrs": { "color": "red", "xray": "1" }
    },
    {
      "type": "wokwi-hc-sr04",
      "id": "ultrasonic1",
      "top": -104.1,
      "left": 139.9,
      "attrs": { "distance": "157" }
    },
    {
      "type": "wokwi-servo",
      "id": "servo1",
      "top": -173.8,
      "left": 251.4,
      "rotate": 270,
      "attrs": {}
    }
  ],
  "connections": [
    [ "nano:GND.2", "led3:C", "black", [ "v-48", "h-38.9", "v-19.6" ] ],
    [ "led3:C", "led2:C", "black", [ "h-9.6", "v-18.8" ] ],
    [ "led2:C", "led1:C", "black", [ "h-9.6", "v-18.8" ] ],
    [ "led1:C", "led4:C", "green", [ "h0" ] ],
    [ "led4:C", "led5:C", "black", [ "h9.6", "v0.4" ] ],
    [ "led5:C", "led6:C", "black", [ "h9.6", "v19.6" ] ],
    [ "nano:5", "led5:A", "gray", [ "v-38.4", "h-10.1", "v-38.4" ] ],
    [ "nano:6", "led2:A", "white", [ "v-72", "h-0.5" ] ],
    [ "nano:7", "led4:A", "limegreen", [ "v-33.6", "h9.1", "v-57.6" ] ],
    [ "nano:8", "led6:A", "magenta", [ "v-38.4", "h18.7", "v-19.2" ] ],
    [ "btn2:2.r", "btn1:2.r", "black", [ "h9.8", "v19.4" ] ],
    [ "btn2:2.r", "btn3:2.r", "black", [ "h9.8", "v-47.8" ] ],
    [ "nano:10", "btn3:1.r", "violet", [ "v-28.8", "h-38.9", "v-86.4" ] ],
    [ "nano:2", "btn1:1.r", "green", [ "v-28.8", "h-134.6" ] ],
    [ "ultrasonic1:VCC", "nano:5V.2", "red", [ "v0" ] ],
    [ "ultrasonic1:TRIG", "nano:A5", "green", [ "v86.4", "h-125.2" ] ],
    [ "ultrasonic1:ECHO", "nano:A4", "green", [ "v96", "h-144.8" ] ],
    [ "ultrasonic1:GND", "nano:GND.3", "black", [ "v0" ] ],
    [ "nano:9", "led3:A", "magenta", [ "v-38.4", "h28.3", "v-19.2" ] ],
    [ "nano:11", "led1:A", "green", [ "v-38.4", "h47.5", "v-57.6" ] ],
    [ "nano:5V.2", "servo1:V+", "red", [ "v0", "h144" ] ],
    [ "nano:GND.3", "servo1:GND", "black", [ "v0", "h144" ] ],
    [ "nano:4", "servo1:PWM", "green", [ "v-28.8", "h249.4" ] ],
    [ "nano:3", "btn2:1.r", "blue", [ "v-28.8", "h-105.6", "v-38.4" ] ],
    [ "nano:5V.2", "btn2:2.r", "red", [ "v0", "h-144", "v-86.4" ] ]
  ],
  "dependencies": {}
}

Okay, thanks for all the input, this has been very informative. I'll come back If we run into any issues.

Alright, so I'm back and the only thing we have to do is integrate two codes together. The robot is going to follow a line, and when it sees the the first obstacle, it will commence this square like maneuver to get around it. After the square as been completed, the car will end back on the line and continue to a wall where it will simply stop.

here is what we have so far.

square maneuver:

#include <Servo.h>

// Pin Definitions
#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11

// Movement Functions with speed parameter
void forward(int speed) {
analogWrite(ENA, speed);
analogWrite(ENB, speed);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
Serial.println("go forward!");
}
void back(int speed) {
analogWrite(ENA, speed);
analogWrite(ENB, speed);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
Serial.println("go back!");
}
void left(int speed) {
analogWrite(ENA, speed);
analogWrite(ENB, speed);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
Serial.println("go left!");
}
void right(int speed) {
analogWrite(ENA, speed);
analogWrite(ENB, speed);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
Serial.println("go right!");
}
void stop() {
digitalWrite(ENA, LOW);
digitalWrite(ENB, LOW);
Serial.println("Stop!");
}

// Object Avoidance: Go around object 540° and realign with line
void go_around_object_540(int goAroundSpeed) {
// 1st 90° turn right (to start going around)

forward(goAroundSpeed);
delay(1500);
stop();
delay(1000);

right(goAroundSpeed);
delay(600);
stop();
delay(1000);

// 1st forward segment
forward(goAroundSpeed);
delay(500);
stop();
delay(1000);

// 2nd 90° turn left
left(goAroundSpeed);
delay(600);
stop();
delay(1000);

// 2nd forward segment
forward(goAroundSpeed);
delay(1000);
stop();
delay(1000);

// 3rd 90° turn left
left(goAroundSpeed);
delay(600);
stop();
delay(1000);

// 3rd forward segment
forward(goAroundSpeed);
delay(1000);
stop();
delay(1000);

// 4th 90° turn left
left(goAroundSpeed);
delay(600);
stop();
delay(1000);

// 4th forward segment
forward(goAroundSpeed);
delay(1000);
stop();
delay(1000);

// 5th 90° turn left
left(goAroundSpeed);
delay(600);
stop();
delay(1000);

// 5th forward segment
forward(goAroundSpeed);
delay(1000);
stop();
delay(1000);

// 6th 90° turn left
left(goAroundSpeed);
delay(600);
stop();
delay(100);

// 6th forward segment
forward(goAroundSpeed);
delay(1000);
stop();
delay(100);

// 7th 90° turn left
left(goAroundSpeed);
delay(600);
stop();
delay(100);

// 7th forward segment
forward(goAroundSpeed);
delay(1000);
stop();
delay(100);

// Final right turn to realign with the original line
right(goAroundSpeed);
delay(600);
stop();
delay(100);

stop();
}

void setup() {
Serial.begin(9600);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
}

void loop() {
// Run the object avoidance routine once
go_around_object_540(145);

// Stop after the maneuver
stop();

current line tracking code:

#include <Servo.h>
#define servoPin 4
Servo myServo;
byte servoHome = 90, servoLeft = 30, servoRight = 150;

// Line Tracking IO define
#define LTL 2
#define LTM 4
#define LTR 10
#define LT_R !digitalRead(LTR)
#define LT_M !digitalRead(LTM)
#define LT_L !digitalRead(LTL)

// motors
#define ENA 5
#define ENB 6
#define IN1 7
#define IN2 8
#define IN3 9
#define IN4 11
#define CARSPEED 107

// SR04
int Echo = A4;
int Trig = A5;
int LEDPin = 13;
int rightDistance = 0;
int leftDistance = 0;
int middleDistance = 0;
int stopDistance = 10;

// Function to measure distance
int Distance_test() {
digitalWrite(Trig, LOW);
delayMicroseconds(2);
digitalWrite(Trig, HIGH);
delayMicroseconds(20);
digitalWrite(Trig, LOW);
float Fdistance = pulseIn(Echo, HIGH);
return (int)(Fdistance / 58);
}

// LED Blinking Function
void BlinkLED() {
for (int i = 0; i < 5; i++) {
digitalWrite(LEDPin, HIGH);
delay(200);
digitalWrite(LEDPin, LOW);
delay(200);
}
}

// Movement Functions
void move(int in1, int in2, int in3, int in4, char dir) {
Serial.print(dir);
analogWrite(ENA, CARSPEED);
analogWrite(ENB, CARSPEED);
digitalWrite(IN1, in1);
digitalWrite(IN2, in2);
digitalWrite(IN3, in3);
digitalWrite(IN4, in4);
}

void forward2() {
move(HIGH, LOW, LOW, HIGH, 'F');
}

void back2() {
move(LOW, HIGH, HIGH, LOW, 'B');
}

void left2() {
move(LOW, HIGH, LOW, HIGH, 'L');
}

void right2() {
move(HIGH, LOW, HIGH, LOW, 'R');
}

void squarecut(){
right2();
delay(600);
stop2();
delay(1000);

// 1st forward segment
forward2();
delay(500);
stop2();
delay(1000);

// 2nd 90° turn left
left2();
delay(600);
stop2();
delay(1000);

// 2nd forward segment
forward2();
delay(1000);
stop2();
delay(1000);

// 3rd 90° turn left
left2();
delay(600);
stop2();
delay(1000);

// 3rd forward segment
forward2();
delay(1000);
stop2();
delay(1000);

// 4th 90° turn left
left2();
delay(600);
stop2();
delay(1000);

// 4th forward segment
forward2();
delay(1000);
stop2();
delay(1000);

// 5th 90° turn left
left2();
delay(600);
stop2();
delay(1000);

// 5th forward segment
forward2();
delay(1000);
stop2();
delay(1000);

// 6th 90° turn left
left2();
delay(600);
stop2();
delay(100);

// 6th forward segment
forward2();
delay(1000);
stop2();
delay(100);

// 7th 90° turn left
left2();
delay(600);
stop2();
delay(100);

// 7th forward segment
forward2();
delay(1000);
stop2();
delay(100);

// Final right turn to realign with the original line
right2();
delay(600);
stop2();
delay(100);
}

void stop2() {
analogWrite(ENA, 0);
analogWrite(ENB, 0);
move(LOW, LOW, LOW, LOW, 'S');
}

// Setup function
void setup() {
Serial.begin(115200);
myServo.attach(servoPin);

pinMode(Echo, INPUT);
pinMode(Trig, OUTPUT);

pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);

pinMode(LEDPin, OUTPUT);

pinMode(LTR, INPUT); // LT_R
pinMode(LTM, INPUT); // LT_M
pinMode(LTL, INPUT); // LT_L

stop2(); // begin in "stop" position
}

void loop() {
myServo.write(servoHome); // forward

if (Distance_test() <= stopDistance) {
stop2();

myServo.write(servoRight);
delay(300);
rightDistance = Distance_test();
myServo.write(servoLeft);
delay(300);
leftDistance = Distance_test();
myServo.write(servoHome);

if (rightDistance > leftDistance) {
Serial.print("DR");
Serial.print(rightDistance);
squarecut();
delay(500);
} else if (leftDistance > rightDistance) {
Serial.print("DL");
Serial.print(leftDistance);
left2();
delay(500);
} else if ((rightDistance <= 10) && (leftDistance <= 10)) { // If both sides are blocked
Serial.print(" BLOCKED");
stop2();
BlinkLED();
delay(1000);
} else {
forward2();
}
}

if (LT_M) {
Serial.print(" LM ");
forward2();
} else if (LT_R) {
Serial.print(" LR ");
right2();
while (LT_R);
} else if (!LT_L) {
Serial.print(" LL ");
left2();
while (LT_L);
}
}

Does it?

Do you understand that your original code raised concerns (post #9, #11, #13) because it used delay() for every event... but that sketch, with the delay() calls, made sense (mia culpa Post #14). You now introduce a requirement that will probably require replacing delay() with a timing mechanism, or your code will run "linearly" (post #11) and the result is unresponsiveness (post #9).

What I am saying, about introducing a totally new requirement after working on the old requirement, is that any work on the old sketch could be of no use.

If you accept the original, linear, unresponsive, sketch, then you should decide on function priority. Is the line more important than the object? Is steering more important than moving? Is stopping more important than steering or moving or the line or the object? Imagine yourself as the driver and the priorities you would follow to keep your vehicle on a line, moving, and avoiding obstacles.

For your sketch to be non-linear, learn to use millis() (and possibly micros()) function to allow time-sharing of events, which is to say, set up time slots for each small task, from checking distances in three servo directions, to changing bearing (vehicle pointing direction), to moving the motors, all in small time-slices... timed by millis() or micros()