The millis seems can not reach the function?

Hi,
The Arduino control CAR from: Obstacle Avoiding Car
https://create.arduino.cc/projecthub/adam/obstacle-avoiding-car-a192d9
running well by Ultrasonic scan + CAR moving alternately.
I try to modified it for Ultrasonic scan and CAR moving together and added some millis, seems not work as excepted, why?
Thanks for help please.
Adam

Original sketch:

#include <Servo.h>          //standard library for the servo
#include <NewPing.h>        //for the Ultrasonic sensor function library.

//L298N motor control pins
const int LeftMotorForward = 6;
const int LeftMotorBackward = 7;
const int RightMotorForward = 5;
const int RightMotorBackward = 4;

//sensor pins
#define trig_pin A1 //analog input 1
#define echo_pin A2 //analog input 2

#define maximum_distance 200
boolean goesForward = false;
int distance = 100;

NewPing sonar(trig_pin, echo_pin, maximum_distance); //sensor function
Servo servo_motor; 

void setup(){

  pinMode(RightMotorForward, OUTPUT);
  pinMode(LeftMotorForward, OUTPUT);
  pinMode(LeftMotorBackward, OUTPUT);
  pinMode(RightMotorBackward, OUTPUT);
  
  servo_motor.attach(9); //our servo pin

  servo_motor.write(115);
  delay(2000);
  distance = readPing();
  delay(100);
  distance = readPing();
  delay(100);
  distance = readPing();
  delay(100);
  distance = readPing();
  delay(100);
}

void loop(){

  int distanceRight = 0;
  int distanceLeft = 0;
  delay(50);

  if (distance <= 20){
    moveStop();
    delay(300);
    moveBackward();
    delay(400);
    moveStop();
    delay(300);
    distanceRight = lookRight();
    delay(300);
    distanceLeft = lookLeft();
    delay(300);

    if (distance >= distanceLeft){
      turnRight();
      moveStop();
    }
    else{
      turnLeft();
      moveStop();
    }
  }
  else{
    moveForward(); 
  }
    distance = readPing();
}

int lookRight(){  
  servo_motor.write(50);
  delay(500);
  int distance = readPing();
  delay(100);
  servo_motor.write(115);
  return distance;
}

int lookLeft(){
  servo_motor.write(170);
  delay(500);
  int distance = readPing();
  delay(100);
  servo_motor.write(115);
  return distance;
  delay(100);
}

int readPing(){
  delay(70);
  int cm = sonar.ping_cm();
  if (cm==0){
    cm=250;
  }
  return cm;
}

void moveStop(){
  
  digitalWrite(RightMotorForward, LOW);
  digitalWrite(LeftMotorForward, LOW);
  digitalWrite(RightMotorBackward, LOW);
  digitalWrite(LeftMotorBackward, LOW);
}

void moveForward(){

  if(!goesForward){

    goesForward=true;
    
    digitalWrite(LeftMotorForward, HIGH);
    digitalWrite(RightMotorForward, HIGH);
  
    digitalWrite(LeftMotorBackward, LOW);
    digitalWrite(RightMotorBackward, LOW); 
  }
}

void moveBackward(){

  goesForward=false;

  digitalWrite(LeftMotorBackward, HIGH);
  digitalWrite(RightMotorBackward, HIGH);
  
  digitalWrite(LeftMotorForward, LOW);
  digitalWrite(RightMotorForward, LOW);
  
}

void turnRight(){

  digitalWrite(LeftMotorForward, HIGH);
  digitalWrite(RightMotorBackward, HIGH);
  
  digitalWrite(LeftMotorBackward, LOW);
  digitalWrite(RightMotorForward, LOW);
  
  delay(500);
  
  digitalWrite(LeftMotorForward, HIGH);
  digitalWrite(RightMotorForward, HIGH);
  
  digitalWrite(LeftMotorBackward, LOW);
  digitalWrite(RightMotorBackward, LOW);
 
  
  
}

void turnLeft(){

  digitalWrite(LeftMotorBackward, HIGH);
  digitalWrite(RightMotorForward, HIGH);
  
  digitalWrite(LeftMotorForward, LOW);
  digitalWrite(RightMotorBackward, LOW);

  delay(500);
  
  digitalWrite(LeftMotorForward, HIGH);
  digitalWrite(RightMotorForward, HIGH);
  
  digitalWrite(LeftMotorBackward, LOW);
  digitalWrite(RightMotorBackward, LOW);
}

modified sketch:

#include <Servo.h>          //standard library for the servo
#include <NewPing.h>        //for the Ultrasonic sensor function library.

//L298N motor control pins
const int LeftMotorForward = 10;
const int LeftMotorBackward = 11;
const int RightMotorForward = 12;
const int RightMotorBackward = 44;

//sensor pins
#define trig_pin 23 //analog input 1
#define echo_pin 22 //analog input 2

#define maximum_distance 200
boolean goesForward = false;
int distance = 100;

NewPing sonar(trig_pin, echo_pin, maximum_distance); //sensor function
Servo servo_motor;

int Tadj = 600;

///////////////////////////////// add millis 20220410

unsigned long READstartMillis;  //some global variables available anywhere in the program
unsigned long READcurrentMillis;
const unsigned long READperiod = Tadj;  //the value is a number of milliseconds

unsigned long lookLeftstartMillis;  //some global variables available anywhere in the program
unsigned long lookLeftcurrentMillis;
const unsigned long lookLeftperiod = Tadj;  //the value is a number of milliseconds

unsigned long lookRightstartMillis;  //some global variables available anywhere in the program
unsigned long lookRightcurrentMillis;
const unsigned long lookRightperiod = Tadj;

unsigned long turnRightstartMillis;  //some global variables available anywhere in the program
unsigned long turnRightcurrentMillis;
const unsigned long turnRightperiod = Tadj;

unsigned long turnLeftstartMillis;  //some global variables available anywhere in the program
unsigned long turnLeftcurrentMillis;
const unsigned long turnLeftperiod = Tadj;

unsigned long moveForwardstartMillis;  //some global variables available anywhere in the program
unsigned long moveForwardcurrentMillis;
const unsigned long moveForwardperiod = Tadj;

///////////////////////////////// add millis 20220410


void setup() {

  pinMode(RightMotorForward, OUTPUT);
  pinMode(LeftMotorForward, OUTPUT);
  pinMode(LeftMotorBackward, OUTPUT);
  pinMode(RightMotorBackward, OUTPUT);

  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);

  servo_motor.attach(14); //our servo pin

  servo_motor.write(115);
  delay(2000);
  distance = readPing();
  delay(100);
  distance = readPing();
  delay(100);
  distance = readPing();
  delay(100);
  distance = readPing();
  delay(100);

  READstartMillis = millis();
  lookLeftstartMillis = millis();
  lookRightstartMillis = millis();
  turnRightstartMillis = millis();
  turnLeftstartMillis = millis();
  moveForwardstartMillis = millis();
}

void loop() {

  int distanceRight = 0;
  int distanceLeft = 0;
  delay(50);

  if (distance <= 20) {
    moveStop();
    delay(300);
    moveBackward();
    delay(400);
    moveStop();
    delay(300);
    /////////////////////////////////////////////////////////////////////////////////
    lookRightcurrentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (lookRightcurrentMillis - lookRightstartMillis >= lookRightperiod)  //test whether the period has elapsed
    {
      distanceRight = lookRight();
      lookRightstartMillis = lookRightcurrentMillis;  //IMPORTANT to save the start time of the current LED state.
    }
    /////////////////////////////////////////////////////////////////////////////
    // distanceRight = lookRight();
    // delay(300);
    /////////////////////////////////////////////////////////////////////////////////
    lookLeftcurrentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
    if (lookLeftcurrentMillis - lookLeftstartMillis >= lookLeftperiod)  //test whether the period has elapsed
    {
      distanceLeft = lookLeft();
      lookLeftstartMillis = lookLeftcurrentMillis;  //IMPORTANT to save the start time of the current LED state.
    }
    /////////////////////////////////////////////////////////////////////////////
    // distanceLeft = lookLeft();
    // delay(300);

    if (distance >= distanceLeft) {

      /////////////////////////////////////////////////////////////////////////////////
      turnRightcurrentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
      if (turnRightcurrentMillis - turnRightstartMillis >= lookLeftperiod)  //test whether the period has elapsed
      {
        turnRight();
        turnRightstartMillis = turnRightcurrentMillis;  //IMPORTANT to save the start time of the current LED state.
      }
      /////////////////////////////////////////////////////////////////////////////

      //  turnRight();
      moveStop();
    }
    else {

      /////////////////////////////////////////////////////////////////////////////////
      turnLeftcurrentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
      if (turnLeftcurrentMillis - turnLeftstartMillis >= lookLeftperiod)  //test whether the period has elapsed
      {
        turnLeft();
        turnLeftstartMillis = turnLeftcurrentMillis;  //IMPORTANT to save the start time of the current LED state.
      }
      /////////////////////////////////////////////////////////////////////////////

      //  turnLeft();
      moveStop();
    }
  }
  else {

    /////////////////////////////////////////////////////////////////////////////////
      moveForwardcurrentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
      if (moveForwardcurrentMillis - moveForwardstartMillis >= lookLeftperiod)  //test whether the period has elapsed
      {
        moveForward();
        moveForwardstartMillis = moveForwardcurrentMillis;  //IMPORTANT to save the start time of the current LED state.
      }
      /////////////////////////////////////////////////////////////////////////////
    //moveForward();
  }
  distance = readPing();
}

int lookRight() {
  servo_motor.write(50);
  delay(500);
  int distance = readPing();
  delay(100);
  servo_motor.write(115);
  return distance;
}

int lookLeft() {
  servo_motor.write(170);
  delay(500);
  int distance = readPing();
  delay(100);
  servo_motor.write(115);
  return distance;
  delay(100);
}

int readPing() {
  delay(70);
  int cm = sonar.ping_cm();
  if (cm == 0) {
    cm = 250;
  }
  return cm;
}

void moveStop() {

  digitalWrite(RightMotorForward, LOW);
  digitalWrite(LeftMotorForward, LOW);
  digitalWrite(RightMotorBackward, LOW);
  digitalWrite(LeftMotorBackward, LOW);
}

void moveForward() {

  if (!goesForward) {

    goesForward = true;

    digitalWrite(LeftMotorForward, HIGH);
    digitalWrite(RightMotorForward, HIGH);

    digitalWrite(LeftMotorBackward, LOW);
    digitalWrite(RightMotorBackward, LOW);
  }
}

void moveBackward() {

  goesForward = false;

  digitalWrite(LeftMotorBackward, HIGH);
  digitalWrite(RightMotorBackward, HIGH);

  digitalWrite(LeftMotorForward, LOW);
  digitalWrite(RightMotorForward, LOW);

}

void turnRight() {

  digitalWrite(LeftMotorForward, HIGH);
  digitalWrite(RightMotorBackward, HIGH);

  digitalWrite(LeftMotorBackward, LOW);
  digitalWrite(RightMotorForward, LOW);

  delay(500);

  digitalWrite(LeftMotorForward, HIGH);
  digitalWrite(RightMotorForward, HIGH);

  digitalWrite(LeftMotorBackward, LOW);
  digitalWrite(RightMotorBackward, LOW);



}

void turnLeft() {

  digitalWrite(LeftMotorBackward, HIGH);
  digitalWrite(RightMotorForward, HIGH);

  digitalWrite(LeftMotorForward, LOW);
  digitalWrite(RightMotorBackward, LOW);

  delay(500);

  digitalWrite(LeftMotorForward, HIGH);
  digitalWrite(RightMotorForward, HIGH);

  digitalWrite(LeftMotorBackward, LOW);
  digitalWrite(RightMotorBackward, LOW);
}

what is expected?
I mean it works, but you "added some millis". what is the reason?

1 Like

I have no clue what you are trying to accomplish with the addition of those conditionals. I can tell you that because of all the delays you will ALWAYS enter those if statements because lookRightperiod, lookLeftperiod, etc are all set to 600. You have way more than 600ms in delays.

1 Like

Thanks.
I like the car continuously moving and Ultrasonic scan at same time, not as was car stop and Ultrasonic scan.

the left and right distance scans are ~1/3 second apart.
do you think their comparison would be accurate if the car is moving?

1 Like

Thanks.
it may be lengthen? or slow down the car speed. I just think if can get the car keep running without stop.

I see many delays and then millis in code salad.
Why it is not correct is that you have not learned the why of millis timing.

I like Nick Gammon's tutorials because he has why in his common sense explanations.

I like turkey bacon. Nick explains doing more than one thing at a time, what and why:

But what if you want to blink the two LEDs at different rates? Like, once a second for LED 1 and twice a second for LED 2?

This is where the delay function doesn't really help.

Let's look at an analogy. Say you want to cook breakfast. You need to cook:

  • Coffee - takes 1 minute

  • Bacon - takes 2 minutes

  • Eggs - takes 3 minutes

Now a seasoned cook would NOT do this:

  • Put coffee on. Stare at watch until 1 minute has elapsed. Pour coffee.

  • Cook bacon. Stare at watch until 2 minutes have elapsed. Serve bacon.

  • Fry eggs. Stare at watch until 3 minutes have elapsed. Serve eggs.

The flaw in this is that whichever way you do it, something is going to be cooked too early (and get cold).

In computer terminology this is blocking . That is, you don't do anything else until the one task at hand is over.

What you are likely to do is this:

  • Start frying eggs. Look at watch and note the time.

  • Glance at watch from time to time. When one minute is up then ...

  • Start cooking bacon. Look at watch and note the time.

  • Glance at watch from time to time. When another minute is up then ...

  • Put coffee on. Look at watch and note the time.

  • When 3 minutes are up, everything is cooked. Serve it all up.

In computer terminology this is non-blocking . That is, keep doing other things while you wait for time to be up.

The full lesson including code kept simple and short.

2 Likes

Please, first get code that will run smoothly together with a smaller code and apply to the car later?

Make led13 blink and watch for a button at the same time. Button can be one jumper if the pinMode is INPUT_PULLUP, safe to ground in a GND or touch the grounded USB box or even wire a real button, might have one with wires in a bin of salvaged parts.

Your RC car sensor takes less time to detect what is 20cm away than 1m away but if you can stop in 20cm or less you don't need to wait for returns from farther to let the motor keep running. You do have to wait for returns before you ping again -- that interval and the car speed make the real "20cm", like how far headlights reach and night driving speed except with sonar, detection time forces decision lag.

1 Like

There is a fundamental difference between using delay() and non-blocking timing which is the base to enable doing multiple things at the same time

If you want to use non-blocking timing the basic requirements are

  • doing all timing non-blocking consequently: Delete ALL delay()s and replace them with non-blocking timing

  • no for-loops, no while-loops

  • ALL looping MUST be done by

function loop()

After reading this I guess you have just a big questionmark inside your head.
How shall I do this ????????????????????????

Yes you are right:
this requires a fundamental restructuring of your code

You can try applying this immidiately to your code.
But I promise you: trying to be fast by applying it direct to your code will end up in slowing you down needing three times longer to make it run

than

learning the basics about non-blocking timing and after learning the basics applying it to your code.

This learning the basics can be based on your project "RC-car" but building it up from scratch with adding only

one thing at a time

I suggest that - as the first thing you take servo looking left / right and write a small demo-code that does only turning the servo left/right based on non-blocking timing.
as a

first attempt on your own

I'm pretty sure that you will have questions. Asking all those questions is the right deepness to really understand the code.

As a first introduction
read this tutorial

Be the change you want to see in the world
best regards Stefan

1 Like

Great!
thank you.

I have a technique that I applied to delay-ridden code using serial, I2C, and GSM. I didn't know I2C well, GSM at all, but I didn't need to, I only needed to get rid of delays.

The GSM code had 13 delays. I turned it into a function (1 entrance) with a switch-case and a case for every step up to delay where the next case would have a timer only I made a common timer for all the cases and put it in front of the switch statement.

Doing that took adding less code than I kept, all the initializing and operations I didn't have to know or look up ran correctly.

// add-a-sketch_un-delay 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/18 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows a general method to get rid of delays in code.
// You could upgrade code with delays to work with add-a-sketch.

#include <avr/io.h>
#include "Arduino.h"

const byte ledPin = 13;
unsigned long delayStart, delayWait;

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Un-Delay Example, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows how to get rid of delays in code.\n" ));

  pinMode( ledPin, OUTPUT );
};


/* The section of the original sketch with delays:
 * 
 * digitalWrite( ledPin, HIGH );   --  0
 * delay( 500 );
 * digitalWrite( ledPin, LOW );    --  1
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  2
 * delay( 250 );
 * digitalWrite( ledPin, LOW );    --  3
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  4
 * delay( 1000 );
 * digitalWrite( ledPin, LOW );    --  5
 * delay( 1000 );
 */

byte blinkStep; // state tracking for BlinkPattern() below

void BlinkPattern()
{
  // This one-shot timer replaces every delay() removed in one spot.  
  // start of one-shot timer
  if ( delayWait > 0 ) // one-shot timer only runs when set
  {
    if ( millis() - delayStart < delayWait )
    {
      return; // instead of blocking, the undelayed function returns
    }
    else
    {
      delayWait = 0; // time's up! turn off the timer and run the blinkStep case
    }
  }
  // end of one-shot timer

  // here each case has a timed wait but cases could change Step on pin or serial events.
  switch( blinkStep )  // runs the case numbered in blinkStep
  {
    case 0 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 0 doing something unspecified here at " ));
    Serial.println( delayStart = millis()); // able to set a var to a value I pass to function
    delayWait = 500; // for the next half second, this function will return on entry.
    blinkStep = 1;   // when the switch-case runs again it will be case 1 that runs
    break; // exit switch-case

    case 1 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 1 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 2;
    break;

    case 2 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 2 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 3;
    break;

    case 3 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 3 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 4;
    break;

    case 4 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 4 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 5;
    break;

    case 5 :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "Case 5 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 0;
    break;
  }
}


void loop()  // runs over and over, see how often
{            
  BlinkPattern();
}

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