How to make a robot move while sensors continue to detect obstacles?

Hello everyone,

I'm pretty new in the great World of Arduino, electronics and coding and after a few weeks of experiments and basic projects, I've managed to make my first autonomous robot. The robot currently works fine, avoiding obstacles, but the problem is that it sometimes happens to get stuck, because some obstacles may hit him in places sensors cannot detect. I could of course make modifications to those sensors positions to improve this aspect, but i would rather prefer a software solution instead, because it would lead me to make several other improvements then and also because there will always be special unexpected situations where the sensors may not detect things.

Currently, what I want is that if the robot goes straight for let's say more than 15 seconds, then it should stop, go back a little, turn and restart this routine until another 15 seconds passed and so on.

The big problem is that I don't know how to do for the sensors to keep working in this case, because the robot doesn't seem to react until this routine is fully achieved, so it will only check sensors state after this routine is complete, about once every 15 seconds. What I want is that those sensors have a priority over the routine, and that if any sensor detects anything anytime, then the robot should perfom another action, no matter what he was doing at that time.

Do you have any idea about how to do that?

Thanks a lot in advance for your help guys!

PS, sorry if there's anything unclear in my text, as I'm not a native english speaker. So if you don't understand something in my issues's description, feel free to ask for clarification!

:slight_smile:

You need to keep looking at the sensors while checking if it is time to turn off the motors.
This seeming to do two things at once is an illustration of a state machine and an example is the blink without delay code in the examples section of the IDE.
The trick is never to use the delay function.

Yes, I think you are right, but then how can I make the servo turn for a certain amount of time without using the delay function?
Also, the ultrasonic sensors use a delay function to work properly, will this be a problem too?

I'll check the blink without delay function anyway to better know how this works
Thanks for your answer :slight_smile:

Also, the ultrasonic sensors use a delay function to work properly, will this be a problem too?

Generally, no - it's a very short delay, particularly compared to the length of time it'll take for your robot to do anything. Small delays for debouncing switches are often used without issue too.

but then how can I make the servo turn for a certain amount of time without using the delay function?

That is what the blink without delay will show you how to do.

If you have trouble understanding the example read this:-
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html

While I'm trying to learn how to use this "blink without delay" function, I thought I could share my code here so that you can tell me if there s anything wrong with it the way it is now.

It works fine as a basic obstacle avoiding robot the way it is now. Uses two ultrasonic sensors at the front and two contact switches as well. There's also one switch to pause it which is useful for testings.

#include <Servo.h>
Servo Droite;
Servo Gauche;

const int serialPeriod = 250;       // only print to the serial console every 1/4 second
unsigned long timeSerialDelay = 0;
//long TempsMarcheAvantMax = 15000;
const int loopPeriod = 20;          // a period of 20ms = a frequency of 50Hz
unsigned long timeLoopDelay = 0;


// specify the trig & echo pins used for the ultrasonic sensors
const int TrigPin = 10;
const int EchoPin = 11;
const int TrigPinGauche = 12;
const int EchoPinGauche = 13;

long unsigned ultrasonic2Distance;
long unsigned ultrasonicGDistance;
int ultrasonic2Duration;
int ultrasonicGDuration;
int OnOff = 4; //pause button
int touchDroite = 7; //right touch sensor for obstacles 
int touchGauche = 6;//left one


void setup()
{
    Serial.begin(9600);
    Droite.attach(8); // servo on digital pin 10
    Gauche.attach(9);
    Droite.write(85);
    Gauche.write(95);
    delay(800);
    Droite.write(95);
    Gauche.write(85);
    delay(800);
    Droite.write(90);
    Gauche.write(90);
  
    // ultrasonic sensor pin configurations
    pinMode(TrigPin, OUTPUT);
    pinMode(EchoPin, INPUT);
    pinMode(OnOff, INPUT);
    pinMode(touchDroite, INPUT);
    pinMode(touchGauche, INPUT);
    pinMode(TrigPinGauche, OUTPUT);
    pinMode(EchoPinGauche, INPUT);
}


void loop()
{
    int etattouchDroite = digitalRead(touchDroite);
    int etattouchGauche = digitalRead(touchGauche);
    debugOutput(); // prints debugging messages to the serial console
    
    if(millis() - timeLoopDelay >= loopPeriod)
    {
        readUltrasonicSensors(); // read and store the measured distances
      readUltrasonicSensors2();
        timeLoopDelay = millis();
    }
    
        int etatBouton = digitalRead(OnOff);//this button is to put the robot in pause mode
     if(etatBouton==HIGH) { 
       Stop();
     }
    
    else if(((ultrasonic2Distance >= 7) || (ultrasonic2Distance < 0)) 
    && ((ultrasonicGDistance >= 6) || (ultrasonicGDistance < 0))){ 
            MarcheAvant();
      }/* The robot will go forward if the distance is superior or equal to 7 centimeters.
      the <0 stuff was beause I had negative values before but it's not necessary as i 
      changed this parameter to unsigned now*/
   else if(ultrasonic2Distance <= 6){
     EviterDroite();
     }
     else if(ultrasonicGDistance <= 6){
     EviterGauche();
     }
     if(etattouchDroite != HIGH) {
       ContournerDroite();       
     }
     if(etattouchGauche != HIGH) {
       ContournerGauche();       
     }
     
}
void Stop(){ // pause mode
  Droite.write(90);
  Gauche.write(90);
}
void MarcheAvant(){ // go forward
  Droite.write(80);
  Gauche.write(100);}

void EviterDroite(){ //avoid right obstacles
  Droite.write(100);
  Gauche.write(80);
  delay(1500);
  Droite.write(80);
  Gauche.write(80);
  delay(1500);
}
void EviterGauche(){ //Avoid left obstacles
  Droite.write(100);
  Gauche.write(80);
  delay(1500);
  Droite.write(100);
  Gauche.write(100);
  delay(1500);
}
void ContournerGauche(){ //Avoid left obstacles after a hit
  Droite.write(100);
  Gauche.write(80);
  delay(1000);
  Droite.write(100);
  Gauche.write(100);
  delay(800);
}

void ContournerDroite(){ //same but for right
  Droite.write(100);
  Gauche.write(80);
  delay(1000);
  Droite.write(80);
  Gauche.write(80);
  delay(800);
}
void readUltrasonicSensors() //first ultrasonic sensor reading
{
    // ultrasonic 2
    digitalWrite(TrigPin, HIGH);
    delayMicroseconds(10);                  // must keep the trig pin high for at least 10us
    digitalWrite(TrigPin, LOW);
    
    ultrasonic2Duration = pulseIn(EchoPin, HIGH);
    ultrasonic2Distance = (ultrasonic2Duration/2)/29;
    if (ultrasonic2Distance > 1000){ 
      ultrasonic2Distance = 50;/*I added these lines because I sometimes get super high 
      reading values like 56766544... it affects the robot in a way that sometimes these 
      readings will cause it to jump to an obstacle avoiding function, even if there is
      actually no obsacle. It seems to happen randomly and I don't see why. 
      Anyway these two lines didn't solved the problem but reduced the frequency of this
      bug apparently.*/
  
    }
    

    
}
void readUltrasonicSensors2()//same thing but for second sensor
{
    // ultrasonic 2
    digitalWrite(TrigPinGauche, HIGH);
    delayMicroseconds(10);                  // must keep the trig pin high for at least 10us
    digitalWrite(TrigPinGauche, LOW);
    
    ultrasonicGDuration = pulseIn(EchoPinGauche, HIGH);
    ultrasonicGDistance = (ultrasonicGDuration/2)/29;
    if (ultrasonicGDistance > 1000){
      ultrasonicGDistance = 50;
    }

    
}

void debugOutput(){ //display stuffs on computer
  int etatBouton=digitalRead(OnOff);
  int etattouchDroite=digitalRead(touchDroite);
    if((millis() - timeSerialDelay) > serialPeriod)
    {
        Serial.print("ultrasonDroit: ");
        Serial.print(ultrasonic2Distance);
        Serial.print("   ");
        Serial.print("UltrasonGauche:");
        Serial.print(ultrasonicGDistance);
        Serial.print("   ");
        Serial.print("cm: ");
        Serial.print(etatBouton);
        Serial.println(etattouchDroite);
        
        timeSerialDelay = millis();
    }
}

The only problem I got with this code, is that the ultrasonic sensors sometimes give completely crazy results, like very high numbers or even negatives values in the first code versions I made!
I m not sure what can be the reason beause this was working perfectly fine with only one sensor, so any suggestion is welcome even if it does not affect the robot too much.

Anyway, if anyone has suggestions for this issue or more hopefully for the initial one, they are all warmly welcomed!
Thanks for your help :slight_smile:

By the way, here is how the robot looks like:

Your issues with the ultrasonics may be that the two sensors are interfering with each other. You need sufficient time to elapse between calling them to ensure that you're not picking up echoes from the other.