Obstacle detecting line follower robot

Hi I’m average Family Guy having two kids. Living in joint family with my parents. My wife have to do many rounds from kitchen to the rooms ,so much that she injured her heels. To help her. I made line follower robot ( Arduino based with 2 ir sensor and l298n motor driver) that carries load upto 15 kg for her assistance. Robot is working fine.
Now the problem is when someone or something comes in his path. As both the DC motors are of high torque (15kg-cm/per motor) . They damage the thing or person in path or dis-balance the food it is carrying.
To avoid that I want the Robot to stop if someone/something is in his path and make some noise with buzzer. And move on his path also stop the buzzer when obstacle removed. I want to do this with ultrasonic range module ( HC-SR04) and active 5v 2 pin buzzer.
Problem is that I don’t know how to do connection of these two extra hardware and what modifications are needed in my Arduino sketch . My code is

#define LS 2 // left sensor
#define RS 3 // right sensor
#define LM1 5 // left motor M1a
#define LM2 4 // left motor M2a
#define RM1 7 // right motor M2a
#define RM2 6 // right motor M2b
void setup()
{
pinMode(LS, INPUT);
pinMode(RS, INPUT);
pinMode(LM1, OUTPUT);
pinMode(LM2, OUTPUT);
pinMode(RM1, OUTPUT);
pinMode(RM2, OUTPUT);
}
void loop()
{
if(digitalRead(LS) && digitalRead(RS)) // Move Forward on line
{
digitalWrite(LM1, HIGH);
digitalWrite(LM2, LOW);
digitalWrite(RM1, HIGH);
digitalWrite(RM2, LOW);
}
if(digitalRead(LS) && !(digitalRead(RS))) // turn left by rotationg left motors in forward and right ones in backward direction
{
digitalWrite(LM1, HIGH);
digitalWrite(LM2, LOW);
digitalWrite(RM1, LOW);
digitalWrite(RM2, HIGH);
}
if(!(digitalRead(LS)) && digitalRead(RS)) // Turn right by rotating right motors in forward and left ones in backward direction
{
digitalWrite(LM1, LOW);
digitalWrite(LM2, HIGH);
digitalWrite(RM1, HIGH);
digitalWrite(RM2, LOW);
}

if(!(digitalRead(LS)) && !(digitalRead(RS))) // Finish line, stop both the motors
{
digitalWrite(LM1, LOW);
digitalWrite(LM2, LOW);
digitalWrite(RM1, LOW);
digitalWrite(RM2, LOW);
}
}

If someone can help. I and my family will be very thankful. Thanks

61ezEwXA1CL.SX425.jpg

You definitely don’t need this library - I’ve seen most people just do the calculation with no library at all, but I use the one found here. Then you can incorporate this code into yours:

#include "SR04.h"
#define TRIG_PIN 12
#define ECHO_PIN 11
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long a;

void setup() {
   Serial.begin(9600);
   delay(1000);
}

void loop() {
   a=sr04.Distance();
   Serial.print(a);
   Serial.println("cm");
   delay(1000);
}

Obviously, I’d use something more meaningful than ‘a’ as the variable there. Then just hook up your 5v and ground, then trig to 12 and echo to 11. Upload it then open the serial monitor and make sure you’re getting decent readings.

Then add another if into your loop:

if (a <= 10) {  // like I said, a should be changed to something more meaningful, and the 10 is the distance in cm you want it to stop before hitting something
digitalWrite(LM1, LOW);
digitalWrite(LM2, LOW);
digitalWrite(RM1, LOW);
digitalWrite(RM2, LOW);
}

This doesn’t use the buzzer obviously, but you’d just define it at the top of the code, then write its pin high in the if loop posted above. Keep in mind I’m a terrible programmer and I’m sure there are better ways to do this, but that should get you going at least.

Compiles but not tested. Hope it helps.

#define LS 2 // left sensor
#define RS 3 // right sensor
#define LM1 5 // left motor M1a
#define LM2 4 // left motor M2a
#define RM1 7 // right motor M2a
#define RM2 6 // right motor M2b

#define PROT_STOP_EXTEND_TIME       3000ul  //3-sec time after obstacle goes away that robot restarts
const int pinBeeper = 9;
const int pinTrigger = 11;
const int pinEcho = 12;
const float obstacleStopDist = 10.0;    //10cm? Whatever works for you

#define BEEP_OFF        0
#define BEEP_SETUP      1
#define BEEP_BEEP       2
#define BEEP_BEEP_TIME  250             //mS beep rate
float
    fdistCM;
byte
    stateBeeper;
    
void setup()
{
    pinMode(LS, INPUT);
    pinMode(RS, INPUT);
    //
    pinMode(LM1, OUTPUT);
    pinMode(LM2, OUTPUT);
    pinMode(RM1, OUTPUT);
    pinMode(RM2, OUTPUT);

    pinMode(pinTrigger, OUTPUT);
    pinMode(pinEcho, INPUT);

    fdistCM = 0.0;
    stateBeeper = BEEP_OFF;
    
}//setup


void ReadUltraSound( void )
{
    digitalWrite(pinTrigger, LOW);
    delayMicroseconds(5);
    digitalWrite(pinTrigger, HIGH);
    delayMicroseconds(10);
    digitalWrite(pinTrigger, LOW);
 
    fdistCM = ((float)pulseIn(pinEcho, HIGH, 10000) / 2.0) / 29.1;
    
}//ReadUltraSound

void DoBeeper( void )
{
    static bool
        condBeeper = false;
    static unsigned long
        timeBeeper;
    unsigned long
        timeNow;
                
    switch( stateBeeper )
    {
        case    BEEP_OFF:
            digitalWrite( pinBeeper, LOW );
            
        break;

        case    BEEP_SETUP:
            timeBeeper = millis();
            condBeeper = false;
            digitalWrite( pinBeeper, LOW );
            stateBeeper = BEEP_BEEP;
            
        break;
        
        case    BEEP_BEEP:
            timeNow = millis();
            if( (timeNow - timeBeeper) >= BEEP_BEEP_TIME )
            {
                stateBeeper ^= 1;
                digitalWrite( pinBeeper, (condBeeper)?HIGH:LOW );
                timeBeeper = timeNow;
            }//if
            
        break;
        
    }//switch
    
}//DoBeeper

void DoLineFollower( void )
{
    static bool
        bProtectiveStopFlag = false;
    static unsigned long
        timeStopExtendTime;
    byte
        statusSensors;
       
    if( bProtectiveStopFlag )
    {
        if( fdistCM > obstacleStopDist )
        {
            if( (millis() - timeStopExtendTime) > PROT_STOP_EXTEND_TIME )
            {
                stateBeeper = BEEP_OFF;
                bProtectiveStopFlag = false;
            }//if                
        }//if
        else
            timeStopExtendTime = millis();
  
        return;
        
    }//if
    else
    {
        if( fdistCM <= obstacleStopDist )
        {
            timeStopExtendTime = millis();
            bProtectiveStopFlag = true;
            stateBeeper = BEEP_SETUP;
            statusSensors = 0x00;   //force motor stop
        }//if
        else
        {
            statusSensors = (digitalRead(LS) == HIGH) ? 0b00000010:0;
            statusSensors |= (digitalRead(RS) == HIGH) ? 0b00000001:0;
            
        }//else
        
    }//else
        
    switch( statusSensors )
    {
        case    0x00:
            digitalWrite(LM1, LOW);
            digitalWrite(LM2, LOW);
            digitalWrite(RM1, LOW);
            digitalWrite(RM2, LOW);
        break;

        case    0x01:
            digitalWrite(LM1, LOW);
            digitalWrite(LM2, HIGH);
            digitalWrite(RM1, HIGH);
            digitalWrite(RM2, LOW);
        break;

        case    0x02:
            digitalWrite(LM1, HIGH);
            digitalWrite(LM2, LOW);
            digitalWrite(RM1, LOW);
            digitalWrite(RM2, HIGH);
        break;

        case    0x03:
            digitalWrite(LM1, HIGH);
            digitalWrite(LM2, LOW);
            digitalWrite(RM1, HIGH);
            digitalWrite(RM2, LOW);
        break;
        
    }//switch
    
}//DoLineFollower

void loop()
{
    ReadUltraSound();
    DoLineFollower();
    DoBeeper();
    
}//loop

Thanks very much for your reply and time. I had not tested your codes and modifications as I'm teaching few kids (they have exams) as my hobby. Will be free in 2-3 days and do the hardware and code modifications. Will let you know if it works or not. Also I don't know anything about programming. My approach is trial and error method Will post if I succeed , and ask if I don't. Thanks again guys . You people are awesome.

Hi, Welcome to the forum.

Please read the first post in any forum entitled how to use this forum. http://forum.arduino.cc/index.php/topic,148850.0.html . Then look down to item #7 about how to post your code. It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :) PS, Using the NewPing Library will make the UltraSonic part of the code much simpler and efficient.

Sorry brother . I’m new to all this. Will correct in future posts .
The picture of circuit is in attachment. Thanks

FWIW, I used to design robots for a living and have food for thought: If your "collaborative" robot is capable of injuring someone you should understand the implications of that and design the safety system of the robot to be equal to the hazard.

Merely commanding a motor controller to "off" doesn''t necessarily make the robot safe. A software failure, disconnection of a pin etc could all lead to a condition where the robot doesn't listen to its sensors and it runs into someone, dumps its load or even tumbles down a set of stairs, possibly injuring someone in the process.

You may want to add a "bumper" strip around the robot to detect collisions and an emergency stop switch that acts to open contactors/relays providing power to the motors. Maybe add some redundant measurement in case of a failure of the ultrasound. Full safety can be a bit of a rabbit's hole (2-channel systems, for instance) but in the end you just need to make sure it's reasonably safe, especially with loved ones around.

Thanks for your suggestion Blackfin .
I am thinking of adding some music from my kids toy gun laying around as the first line of Defence

Second is that I have noticed that my robot is consuming around 1.8 ampere from 12 volt battery with load. I have checked the current consumption with little resistance it easily goes above 2 ampere. Mostly between 2.10 and 2.25 amps .
So after reading your safety opinion I am thinking of adding 12v 2amp fuse at beginning of my circuit from battery positive terminal. Fuse will blow up if some sensors stop working.
What do you think. Any suggestions thanks.

Hello again Blackfin. I am having spare Arduino uno . L298n driver. Also pair of ir sensor and multimeter.
I made all the connections as described in the sketch given by you and check the output of the motor driver from the multimeter it seems the sketch is working. But not the buzzer .
Correct me if I am wrong I have two pin (vcc, gnd) active buzzer (pic in attachment). I have connected vcc/positive pin of buzzer to Digital Pin 9 and gnd/negative to gnd of Arduino
However much needed thing that was stopping the robot if anyone comes in the range of ultrasonic range sensor is working. thanks very much man. Very thankful to you

Pradeepkumarluhani: Hello again Blackfin. I am having spare Arduino uno . L298n driver. Also pair of ir sensor and multimeter. I made all the connections as described in the sketch given by you and check the output of the motor driver from the multimeter it seems the sketch is working. But not the buzzer . Correct me if I am wrong I have two pin (vcc, gnd) active buzzer (pic in attachment). I have connected vcc/positive pin of buzzer to Digital Pin 9 and gnd/negative to gnd of Arduino However much needed thing that was stopping the robot if anyone comes in the range of ultrasonic range sensor is working. thanks very much man. Very thankful to you

Oops, sorry about that. Add the line:

pinMode(pinBeeper, OUTPUT );

to setup(). I neglected to add that so the pin is acting as an input and it not driving the beeper.

Pradeepkumarluhani: Thanks for your suggestion Blackfin . I am thinking of adding some music from my kids toy gun laying around as the first line of Defence

Second is that I have noticed that my robot is consuming around 1.8 ampere from 12 volt battery with load. I have checked the current consumption with little resistance it easily goes above 2 ampere. Mostly between 2.10 and 2.25 amps . So after reading your safety opinion I am thinking of adding 12v 2amp fuse at beginning of my circuit from battery positive terminal. Fuse will blow up if some sensors stop working. What do you think. Any suggestions thanks.

I think any circuit protection (fuse or circuit breaker) is a good idea for sources that can deliver enough power to generate significant heat in conductors, components and the like.

One thing to consider with motors is that they draw large current under load or when starting, often many times what they do just to maintain steady speed on a flat surface. An incorrectly sized- or typed-fuse can nuisance trip (blow when not needed, in a very annoying way). Running fuses over their rated value for short periods of time can also "age" fuses, increasing the chance of nuisance tripping.

So a fuse or CB is definitely good just make sure it's sized and typed right.

hi again Blackfin can you please check the code which i uploaded to arduino uno ( specially the beep part, as i observed digital pin 9 is not showing voltage on multimeter nor any sound with buzzer in any condition). thanks . code is

#define LS 2 // left sensor
#define RS 3 // right sensor
#define LM1 5 // left motor M1a
#define LM2 4 // left motor M2a
#define RM1 7 // right motor M2a
#define RM2 6 // right motor M2b

#define PROT_STOP_EXTEND_TIME       3000ul  //3-sec time after obstacle goes away that robot restarts
const int pinBeeper = 9;
const int pinTrigger = 11;
const int pinEcho = 12;
const float obstacleStopDist = 10.0;    //10cm? Whatever works for you

#define BEEP_OFF        0
#define BEEP_SETUP      1
#define BEEP_BEEP       2
#define BEEP_BEEP_TIME  250             //mS beep rate
float
    fdistCM;
byte
    stateBeeper;
    
void setup()
{
    pinMode(LS, INPUT);
    pinMode(RS, INPUT);
    //
    pinMode(LM1, OUTPUT);
    pinMode(LM2, OUTPUT);
    pinMode(RM1, OUTPUT);
    pinMode(RM2, OUTPUT);

    pinMode(pinTrigger, OUTPUT);
    pinMode(pinEcho, INPUT);
    pinMode(pinBeeper, OUTPUT );
    fdistCM = 0.0;
    stateBeeper = BEEP_OFF;
    
}//setup


void ReadUltraSound( void )
{
    digitalWrite(pinTrigger, LOW);
    delayMicroseconds(5);
    digitalWrite(pinTrigger, HIGH);
    delayMicroseconds(10);
    digitalWrite(pinTrigger, LOW);
 
    fdistCM = ((float)pulseIn(pinEcho, HIGH, 10000) / 2.0) / 29.1;
    
}//ReadUltraSound

void DoBeeper( void )
{
    static bool
        condBeeper = false;
    static unsigned long
        timeBeeper;
    unsigned long
        timeNow;
                
    switch( stateBeeper )
    {
        case    BEEP_OFF:
            digitalWrite( pinBeeper, LOW );
            
        break;

        case    BEEP_SETUP:
            timeBeeper = millis();
            condBeeper = false;
            digitalWrite( pinBeeper, LOW );
            stateBeeper = BEEP_BEEP;
            
        break;
        
        case    BEEP_BEEP:
            timeNow = millis();
            if( (timeNow - timeBeeper) >= BEEP_BEEP_TIME )
            {
                stateBeeper ^= 1;
                digitalWrite( pinBeeper, (condBeeper)?HIGH:LOW );
                timeBeeper = timeNow;
            }//if
            
        break;
        
    }//switch
    
}//DoBeeper

void DoLineFollower( void )
{
    static bool
        bProtectiveStopFlag = false;
    static unsigned long
        timeStopExtendTime;
    byte
        statusSensors;
       
    if( bProtectiveStopFlag )
    {
        if( fdistCM > obstacleStopDist )
        {
            if( (millis() - timeStopExtendTime) > PROT_STOP_EXTEND_TIME )
            {
                stateBeeper = BEEP_OFF;
                bProtectiveStopFlag = false;
            }//if                
        }//if
        else
            timeStopExtendTime = millis();
  
        return;
        
    }//if
    else
    {
        if( fdistCM <= obstacleStopDist )
        {
            timeStopExtendTime = millis();
            bProtectiveStopFlag = true;
            stateBeeper = BEEP_SETUP;
            statusSensors = 0x00;   //force motor stop
        }//if
        else
        {
            statusSensors = (digitalRead(LS) == HIGH) ? 0b00000010:0;
            statusSensors |= (digitalRead(RS) == HIGH) ? 0b00000001:0;
            
        }//else
        
    }//else
        
    switch( statusSensors )
    {
        case    0x00:
            digitalWrite(LM1, LOW);
            digitalWrite(LM2, LOW);
            digitalWrite(RM1, LOW);
            digitalWrite(RM2, LOW);
        break;

        case    0x01:
            digitalWrite(LM1, LOW);
            digitalWrite(LM2, HIGH);
            digitalWrite(RM1, HIGH);
            digitalWrite(RM2, LOW);
        break;

        case    0x02:
            digitalWrite(LM1, HIGH);
            digitalWrite(LM2, LOW);
            digitalWrite(RM1, LOW);
            digitalWrite(RM2, HIGH);
        break;

        case    0x03:
            digitalWrite(LM1, HIGH);
            digitalWrite(LM2, LOW);
            digitalWrite(RM1, HIGH);
            digitalWrite(RM2, LOW);
        break;
        
    }//switch
    
}//DoLineFollower

void loop()
{
    ReadUltraSound();
    DoLineFollower();
    DoBeeper();
    
}//loop

Replace state BEEP_BEEP code with this:

        case    BEEP_BEEP:
            timeNow = millis();
            if( (timeNow - timeBeeper) >= BEEP_BEEP_TIME )
            {
                condBeeper ^= 1;
                digitalWrite( pinBeeper, (condBeeper)?HIGH:LOW );
                timeBeeper = timeNow;
            }//if
            
        break;

The current code has "stateBeeper ^= 1;" which is surely not helping things. :)

Blackfin: I think any circuit protection (fuse or circuit breaker) is a good idea for sources that can deliver enough power to generate significant heat in conductors, components and the like.

If you wish to protect against the consequences of catastrophic failure, you use a fuse - the device is inoperable.

If you wish to protect against a malfunction of operation to prevent catastrophic failure but allow the system to be re-activated when the operation has been corrected, you use a circuit breaker.

As in your house. Circuit breakers which you can reset when you figure out that the kettle element has burned out, council fuses in case the rats have shorted out the "fuse" box.

Hello Blackfin . Today I again uploaded your code with latest modification and tested without chassis and motors with multimeter . and HURRAY to your hard work it worked. As I placed my hand on ultrasonic sensor the buzzer sounds beep-beep and motor driver stops output of voltage. I can't tell you how much reliefed I was. You are great man. Will implement all the hardware in 3-4 days and will tell you. But I think it will work now. Thanks from all in my family.

Hi, @Backfin nice bit of code, very readable and good for learners, got most of the common C++ statements and function examples.

Tom.... :)

Hi today I tested the hardware on my kids chassis and motors as prototype. Worked almost fine. Within few days I will apply this new code and sensors to Main Robot.
Little interesting thing is that my robot Travels on both sides from kitchen to room and again from room to kitchen on single line.
I do this with the help of applying two dpdt switches on both motors and one dpdt switch between output of both pair of infrared sensor and input pins of audrino 2 and 3.
I know it sounds funny but as you know I don’t know anything about coding so this was only my way to move robot back and forth on the same line now I have to add one more dpdt switch for ultrasonic sensor. Any suggestions from anyone. Thanks

Hi. Glad to hear it's working for you. You say it worked "almost fine." :/ Is there anything specific that you're not happy with re the existing code?

re the DPDT switches: you're just using those to switch "fwd/rev" on the motors and the sensors left to right? Or...?

"Almost fine". I think I have to reduce ultrasonic range from 10cm. Will tell you more after making and testing final robot.

"Dpdt switch" I am just using those to switch "fwd/rev" on the motors and the sensors pair from front of robot to back ( as my four ir sensor are constantly on with vcc and gnd connection. However dpdt switches the input of Arduino pin 2 & 3 from front to back) same approach will be for two piece of ultrasonic sensor one in front one in back. Thanks

Also just out of curiosity. A thing came to my mind if we connect 3.3 volt output of Arduino to input of any free digital input pin (like pin no 10 is free here) with on/off switch and run the Arduino to see if pin 10 is high then follow original code or (low) then follow code 2 (modifications are: 1. #define LS 3 // left sensor

define RS 2 // right sensor

2.case 0x01: digitalWrite(LM1, HIGH); digitalWrite(LM2, LOW); digitalWrite(RM1, LOW); digitalWrite(RM2, HIGH); break;

case 0x02: digitalWrite(LM1, LOW); digitalWrite(LM2, HIGH); digitalWrite(RM1, HIGH); digitalWrite(RM2, LOW); break;

It will replace three dpdt ( two for motors+one for ir sensor) with one little one on/off switch also will remove one pair of ir sensor. But again it's in my mind. I don't know whether it is practically possible. Thanks again. Basics are working now.