Using an alternative to delay

I am trying to make an obstacle avoidance robot out of an old R/C car I have. currently my code has delay functions to ensure the car backs up all the way to clear the obstacle and so that it alternates between turning right and left. The problem is that the delay (as I'm sure you know) completely stops all other actions so in that time it isn't sensing for obstacles. I think you could use millis to fix this but I really don't know how it works. Could someone explain a good way to fix my problem?

#include <NewPing.h>
#define TRIGGER_PIN 11
#define ECHO_PIN 12
#define MAX_DISTANCE 50 //max distance to ping for
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
const int backMotor1 = 6;
const int backMotor2 = 7;
const int enablePin = 9;
const int frontMotor1 = 4;
const int frontMotor2 = 5;
void setup() 
{
  Serial.begin(9600);
  pinMode(frontMotor1, OUTPUT);
  pinMode(frontMotor2, OUTPUT);
  pinMode(backMotor1, OUTPUT);
  pinMode(backMotor2, OUTPUT);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, LOW);
}

void loop() 
{
  delay(50);
  unsigned int uS = sonar.ping();
  int distance = sonar.ping_cm();
  Serial.print("Ping: ");
  Serial.print(uS / US_ROUNDTRIP_CM);
  Serial.println("cm");
  if((distance > 20) || (distance == 0))
  {
  digitalWrite(enablePin, HIGH);
  digitalWrite(frontMotor1, HIGH);
  digitalWrite(frontMotor2, LOW);
  digitalWrite(backMotor1, LOW);
  digitalWrite(backMotor2, HIGH);
  delay(1000);
  digitalWrite(frontMotor1, LOW);
  digitalWrite(frontMotor2, HIGH);
  delay(1000);
  }
  if((distance >= 1) && (distance < 20))
  { 
    digitalWrite(enablePin, HIGH);
    digitalWrite(frontMotor1, LOW);
    digitalWrite(frontMotor2, HIGH);
    digitalWrite(backMotor1, HIGH);
    digitalWrite(backMotor2, LOW);
    delay(1000);
    
  }
  if((distance > 20) || (distance == 0))
  {
  digitalWrite(enablePin, HIGH);
  digitalWrite(frontMotor1, LOW);
  digitalWrite(frontMotor2, HIGH);
  digitalWrite(backMotor1, LOW);
  digitalWrite(backMotor2, HIGH);
  }
  if((distance >= 1) && (distance < 20))
  { 
    digitalWrite(enablePin, HIGH);
    digitalWrite(frontMotor1, HIGH);
    digitalWrite(frontMotor2, LOW);
    digitalWrite(backMotor1, HIGH);
    digitalWrite(backMotor2, LOW);
    delay(1000);
  }
}

Take a look at the BlinkWithoutDelay in Examples>Digital

It will show you how to delay something without holding up your code.

Even though I am looking at the example I'm still having trouble seeing how to fit it into my code

Huntechr1:
I think you could use millis to fix this but I really don't know how it works

Then I think, with respect, it's time you stopped trying to progress until you do.

So here's my advice: take the BlinkwithOutDelay sketch and dissect it line by line until you fully understand what it's doing. It's too important a concept not to be comfortable with.

Once you have that clear in your mind, modify the sketch to use different times for on and off, then develop it to do that for more than one LED.

That's what I did when I was getting my mind round it.

I was writing the above while dmworking247 replied and you responded...

Huntechr1:
Even though I am looking at the example I'm still having trouble seeing how to fit it into my code

Forget the code for a moment (or as long as necessary) and write down in English the steps you would take if YOU the human stopped at a wall and then backed up for a stipulated time, while doing other stuff.

Ok, I guess I will have to spend some time tomorrow just trying to figure this out

Huntechr1:
Ok, I guess I will have to spend some time tomorrow just trying to figure this out

That will be a worthwhile investment, verily.

And I was serious when I said forget the coding.... do it in English first. Write everything down.

Huntechr1:
...my code has delay functions to ensure the car backs up all the way to clear the obstacle ...

This is a very common short-cut in early progtamming.
There is no 'ensuring' the car backs up happening here!
You are telling the car to back up, then going off to lunch...!

-- if you tell your dog not to eat the roast, then go out for an hour... what are the chances the roast will be there when you return?!,

Apart from delay() being a blight on well written .state aware' code, using this technique has no provision for a wheel slipping or other obstacle that might affect the distance travelled.

Read about closed loops, and consider sensing when the vehicle has moved to the desired position... yes, it's more difficult - but its also more accurate and reliable.

Huntechr1:
Ok, I guess I will have to spend some time tomorrow just trying to figure this out

Learning how to use millis in the Arduino environment was possibly the most useful and important part of all of it. There are several very well written examples - look at the 'Useful Links' thread at the top of this sub-forum's listing.

The trick is that in BlinkWithoutDelay one compares two times (a start time (called previousMillis) and the current time (conveniently called currentMillis)) and only does something if a certain duration has passed.

In combination with a state machine implementation, the below code that implements a non-blocking delay can be used.

/*
  non blocking delay
  returns false if delay in progress, else true

  assumes a global variable currentMillis that is set to the current time
*/
bool doDelay(unsigned long duration)
{
  // start time
  static unsigned long starttime = 0;

  // if delay not started
  if(starttime == 0)
  {
    // set the start time of the delay
    starttime = currentMillis;
  }

  // if delay has lapsed
  if(currentMillis - starttime >= duration)
  {
    // reset start time for the next time that we need the delay function
    starttime = 0;
    // indicate that delay has lapsed
    return true;
  }

  // indicate that delay in progress
  return false;
}

Mostly posted in the hope that the comments help in understanding the above or understand BlinkWithoutDelay. currentMillis is a global variable.

Note that this is basically only useful for a statemachine. Example

// required global variables
int currentState = 0;
unsigned long currentMillis;

void setup()
{
}

void loop()
{

  // get current time
  currentMillis = millis();

  // simple statemachine implementation
  switch(currentState)
  {
    case 0:
      // do something
      ...
      ...
      // go to next state
      currentState++;
      break;
    case 1:
      // start delay / check if lapsed
      if(deDelay(1000) == true)
      {
        // go to next state
        currentstate++;
      }
      break;
    case 2:
      // do something else
      ...
      ...
      // go back to first state (0)
      currentState = 0;
      break;

  } // end_of_switch
}

bool doDelay(unsiged long duration)
{
  // see previous code
  ...
  ...
}
unsigned int uS = sonar.ping();
  int distance = sonar.ping_cm();
  Serial.print("Ping: ");
  Serial.print(uS / US_ROUNDTRIP_CM);

You didn't look closely enough at my reply in your other thread yesterday.
What's the point of doing 'sonar.ping()' immediately followed by 'sonar.ping_cm()'?
You follow it by converting the microseconds value from 'sonar.ping()' to cm anyway, in your 'Serial.print()'.
In the reply yesterday, I showed you how to print the return value of 'sonar.ping_cm()'.
All you really need is:-

int distance = sonar.ping_cm();     // Send ping and get distance in cm
Serial.print("Ping: ");
Serial.print(distance);             // Print the distance

I noticed something else that you've overlooked, too. In the 'if' statements in the code you posted, you haven't made any allowance for what happens if the distance is exactly 20cm, only if it's larger or smaller than 20cm.

You've also doubled up on each of the 'if' statements, doing a different thing each time. Of course, the first of each will only happen for a split second before the second is executed.
These are your 4 conditional statements:-
(See the similarities?)

if((distance > 20) || (distance == 0))
....
if((distance >= 1) && (distance < 20))
....
if((distance > 20) || (distance == 0))
....
if((distance >= 1) && (distance < 20))
....

I realise that you're re-writing the code, but thought that I should point these things out anyway, so that you're aware.

Edit: Another quick note - I agree with JimboZA. Write things in order in English first, step-by-step, then write code to accomplish those steps. That's how I always write my programs.

JimboZA:
Forget the code for a moment (or as long as necessary) and write down in English the steps you would take if YOU the human stopped at a wall and then backed up for a stipulated time, while doing other stuff.

The demo Several Things at a Time is an extended example of BWoD - it may help to clarify things.

...R