i am unable to run obstacle avoidance properly. please help.

this is my code here but i am unable to run obstacle avoidance properly. i am able to get it running when i press 7 on the ir remote. But it does not measure the distance continuously. it is actually a multifunction program for my robot car. everything else like the speed control is working.

#include <IRremote.h>
#include <Servo.h>
int servoPin = 3;
int servoPos = 130;
Servo myServo;

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

float t;
float distanceV = 1000;
float speedV = 100;

int trig = A5;
int echo = A4;
int pingtime;
int pingTime;
int pingTime2;
int pingTime3;
int pingread;
int pingRead;
int pingRead2;
int pingRead3;
int j;

int irSensor = 12;
IRrecv myIR(irSensor);
decode_results cmd;

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
myIR.enableIRIn();
myIR.blink13(true);
Serial.begin(9600);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(ENA, OUTPUT);
pinMode(ENB, OUTPUT);

myServo.attach(servoPin);
pinMode(trig, OUTPUT);
pinMode(echo, INPUT);

}

void servoMeasure(){
for(j=95;j<=180;j=j+1){
myServo.write(j);
delay(9);
}
digitalWrite(trig,LOW);
delayMicroseconds(10);
digitalWrite(trig,HIGH);
delayMicroseconds(10);
digitalWrite(trig,LOW);
pingTime=pulseIn(echo,HIGH);
delay(25);
pingRead=pingTime/15;
for(j=180;j>=95;j=j-1){
myServo.write(j);
delay(9);
}
digitalWrite(trig,LOW);
delayMicroseconds(10);
digitalWrite(trig,HIGH);
delayMicroseconds(10);
digitalWrite(trig,LOW);
pingTime2=pulseIn(echo,HIGH);
delay(25);
pingRead2=pingTime2/15;
for(j=95;j>=1;j=j-1){
myServo.write(j);
delay(9);
}
digitalWrite(trig,LOW);
delayMicroseconds(10);
digitalWrite(trig,HIGH);
delayMicroseconds(10);
digitalWrite(trig,LOW);
pingTime3=pulseIn(echo,HIGH);
delay(25);
pingRead3=pingTime3/15;
for(j=1;j<=95;j=j+1){
myServo.write(j);
delay(9);
}

}

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

}

void stopped(){
digitalWrite(ENA, LOW);
digitalWrite(ENB, LOW);
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
}

void backward(float speedV){
analogWrite(ENA,speedV);
analogWrite(ENB,speedV);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);

}

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

}

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

}

void distance(){
digitalWrite(trig,LOW);
delayMicroseconds(10);
digitalWrite(trig,HIGH);
delayMicroseconds(10);
digitalWrite(trig,LOW);
pingtime=pulseIn(echo,HIGH);
delayMicroseconds(5);
pingread=pingtime/15;

}

void setspeed(){
Serial.println("Set Speed");
delay(500);
while(myIR.decode(&cmd) == 0){

}

if(cmd.value == 0xFF6897){
Serial.println("speed=1");
speedV=50;
}
if(cmd.value == 0xFF9867){
Serial.println("speed=2");
speedV=75;
}
if(cmd.value == 0xFFB04F){
Serial.println("speed=3");
speedV=100;
}
if(cmd.value == 0xFF30CF){
Serial.println("speed=4");
speedV=150;
}
if(cmd.value == 0xFF18E7){
Serial.println("speed=5");
speedV=200;
}
if(cmd.value == 0xFF7A85){
Serial.println("speed=6");
speedV=255;
}

}

void setdistance(){
Serial.println("Set distance mode");
delay(500);
myIR.resume();
while(myIR.decode(&cmd) == 0){

}

if(cmd.value == 0xFF6897){
Serial.println("Distance=1");
distanceV=250;
}
if(cmd.value == 0xFF9867){
Serial.println("Distance=2");
distanceV=500;
}
if(cmd.value == 0xFFB04F){
Serial.println("Distance=3");
distanceV=1000;
}
if(cmd.value == 0xFF30CF){
Serial.println("Distance=4");
distanceV=1500;
}
if(cmd.value == 0xFF18E7){
Serial.println("Distance=5");
distanceV=2000;
}
if(cmd.value == 0xFF7A85){
Serial.println("Distance=6");
distanceV=3000;
}

}

void distance2(){
forward(255);
distance();
Serial.println(pingread);

}

void obstacle(){
distance();
Serial.println(pingread);
if(pingread > 50){
distance2();

}

if(pingread < 40){
stopped();
servoMeasure();
}

if(pingRead < pingRead3){
right(255);
distance();
if(pingread > 40){
distance2();
}

}

if(pingRead > pingRead3){
left(255);
distance();
if(pingread > 40){
distance2();
}

}
}

void loop() {
// put your main code here, to run repeatedly:

Serial.println(cmd.value);
distance();
delay(100);

Serial.println(cmd.value,HEX);

while(myIR.decode(&cmd) == 0){

}
delay(100);

myIR.resume();
if (cmd.value == 0xFF629D){
forward(speedV);
delay(distanceV);
stopped();

}

if (cmd.value == 0xFFA857){
backward(speedV);
delay(distanceV);
stopped();

}

if (cmd.value == 0xFFC23D){
right(speedV);
delay(distanceV);
stopped();

}

if (cmd.value == 0xFF22DD){
left(speedV);
delay(distanceV);
stopped();

}

if (cmd.value == 0xFF02FD){
stopped();
delay(250);

}

if (cmd.value == 0xFF52AD){
setspeed();

}

if (cmd.value == 0xFF42BD){
setdistance();
}

if (cmd.value == 0xFF10EF){

if(pingread > 50){
distance2();

}

if(pingread < 40){
stopped();
servoMeasure();
}

if(pingRead < pingRead3){
right(255);
distance();
if(pingread > 40){
distance2();
}

}

if(pingRead > pingRead3){
left(255);
distance();
if(pingread > 40){
distance2();
}

}
}

}

Here they want it in code tags. Otherwise they will get all huffy around here.

#include <IRremote.h>
#include <Servo.h>


int servoPin = 3;
int servoPos = 130;
Servo myServo;

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

float t;
float distanceV = 1000;
float speedV = 100;

int trig = A5;
int echo = A4;
int pingtime;
int pingTime;
int pingTime2;
int pingTime3;
int pingread;
int pingRead;
int pingRead2;
int pingRead3;
int j;

int               irSensor = 12;
IRrecv            myIR(irSensor);
decode_results    cmd;

void setup() {
   
  Serial.begin(9600);
  myIR.enableIRIn();
  myIR.blink13(true);
  Serial.begin(9600);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  myServo.attach(servoPin);
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
}


void servoMeasure() {
   
  for (j = 95; j <= 180; j = j + 1) {
    myServo.write(j);
    delay(9);
  }
  digitalWrite(trig, LOW);
  delayMicroseconds(10);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  pingTime = pulseIn(echo, HIGH);
  delay(25);
  pingRead = pingTime / 15;
  for (j = 180; j >= 95; j = j - 1) {
    myServo.write(j);
    delay(9);
  }
  digitalWrite(trig, LOW);
  delayMicroseconds(10);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  pingTime2 = pulseIn(echo, HIGH);
  delay(25);
  pingRead2 = pingTime2 / 15;
  for (j = 95; j >= 1; j = j - 1) {
    myServo.write(j);
    delay(9);
  }
  digitalWrite(trig, LOW);
  delayMicroseconds(10);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  pingTime3 = pulseIn(echo, HIGH);
  delay(25);
  pingRead3 = pingTime3 / 15;
  for (j = 1; j <= 95; j = j + 1) {
    myServo.write(j);
    delay(9);
  }
}


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


void stopped() {
   
  digitalWrite(ENA, LOW);
  digitalWrite(ENB, LOW);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}


void backward(float speedV) {
   
  analogWrite(ENA, speedV);
  analogWrite(ENB, speedV);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}


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


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


void distance() {
   
  digitalWrite(trig, LOW);
  delayMicroseconds(10);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  pingtime = pulseIn(echo, HIGH);
  delayMicroseconds(5);
  pingread = pingtime / 15;
}



void setspeed() {
   
  Serial.println("Set Speed");
  delay(500);
  while (myIR.decode(&cmd) == 0) { }
  if (cmd.value == 0xFF6897) {
    Serial.println("speed=1");
    speedV = 50;
  }
  if (cmd.value == 0xFF9867) {
    Serial.println("speed=2");
    speedV = 75;
  }
  if (cmd.value == 0xFFB04F) {
    Serial.println("speed=3");
    speedV = 100;
  }
  if (cmd.value == 0xFF30CF) {
    Serial.println("speed=4");
    speedV = 150;
  }
  if (cmd.value == 0xFF18E7) {
    Serial.println("speed=5");
    speedV = 200;
  }
  if (cmd.value == 0xFF7A85) {
    Serial.println("speed=6");
    speedV = 255;
  }
}


void setdistance() {
  
  Serial.println("Set distance mode");
  delay(500);
  myIR.resume();
  while (myIR.decode(&cmd) == 0) { }
  if (cmd.value == 0xFF6897) {
    Serial.println("Distance=1");
    distanceV = 250;
  }
  if (cmd.value == 0xFF9867) {
    Serial.println("Distance=2");
    distanceV = 500;
  }
  if (cmd.value == 0xFFB04F) {
    Serial.println("Distance=3");
    distanceV = 1000;
  }
  if (cmd.value == 0xFF30CF) {
    Serial.println("Distance=4");
    distanceV = 1500;
  }
  if (cmd.value == 0xFF18E7) {
    Serial.println("Distance=5");
    distanceV = 2000;
  }
  if (cmd.value == 0xFF7A85) {
    Serial.println("Distance=6");
    distanceV = 3000;
  }
}



void distance2() {
   
  forward(255);
  distance();
  Serial.println(pingread);
}

void obstacle() {
   
  distance();
  Serial.println(pingread);
  if (pingread > 50) {
    distance2();
  }
  if (pingread < 40) {
    stopped();
    servoMeasure();
  }
  if (pingRead < pingRead3) {
    right(255);
    distance();
    if (pingread > 40) {
      distance2();
    }
  }
  if (pingRead > pingRead3) {
    left(255);
    distance();
    if (pingread > 40) {
      distance2();
    }
  }
}




void loop() {

  Serial.println(cmd.value);
  distance();
  delay(100);
  Serial.println(cmd.value, HEX);
  while (myIR.decode(&cmd) == 0) {
  }
  delay(100);
  myIR.resume();
  if (cmd.value == 0xFF629D) {
    forward(speedV);
    delay(distanceV);
    stopped();
  }
  if (cmd.value == 0xFFA857) {
    backward(speedV);
    delay(distanceV);
    stopped();
  }
  if (cmd.value == 0xFFC23D) {
    right(speedV);
    delay(distanceV);
    stopped();
  }
  if (cmd.value == 0xFF22DD) {
    left(speedV);
    delay(distanceV);
    stopped();
  }
  if (cmd.value == 0xFF02FD) {
    stopped();
    delay(250);
  }
  if (cmd.value == 0xFF52AD) {
    setspeed();

  }
  if (cmd.value == 0xFF42BD) {
    setdistance();
  }
  if (cmd.value == 0xFF10EF) {
    if (pingread > 50) {
      distance2();
    }
    if (pingread < 40) {
      stopped();
      servoMeasure();
    }
    if (pingRead < pingRead3) {
      right(255);
      distance();
      if (pingread > 40) {
        distance2();
      }
    }
    if (pingRead > pingRead3) {
      left(255);
      distance();
      if (pingread > 40) {
        distance2();
      }
    }
  }
}

-jim lee

With all of those 'while' loops, your sketch is going to be mostly locked up waiting for an IR command. I think you need a Finite State Machine design to allow your sketch to make decisions BETWEEN commands from the IR remote.

// Example Finite State Machine
//
// The pin 13 LED is blinking ON for 0.5s and OFF for 4.5s.
// Until a LOW on D6 triggers it to immediately go ON for 2s, and then return to the 5s cycling.


enum FSMStages {ENTERING, RUNNING, EXITING};
typedef void (FSMStateFunction)(FSMStages stage);


// A function for each state the FSM can be in
void BlinkOn(enum FSMStages stage);
void BlinkOff(enum FSMStages stage);
void ButtonPressed(enum FSMStages stage);


const unsigned long BLINK_ON_INTERVAL = 500;
const unsigned long BLINK_OFF_INTERVAL = 4500;
const unsigned long BUTTON_PRESSED_INTERVAL = 2000;


const byte Button_IPPin = 6;  // INPUT_PULLUP pin for the button


void setup()
{
  Serial.begin(115200);


  pinMode(Button_IPPin, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);


  // Starting in the BlinkOn state
  FSMEnterState(BlinkOn);
}


void loop()
{
  FSMRun();
}


void BlinkOn(enum FSMStages stage)
{
  static unsigned long startTime = 0;
  unsigned long currentTime = millis();
  switch (stage)
  {
    case FSMStages::ENTERING:
      Serial.println("On");
      digitalWrite(LED_BUILTIN, HIGH); // ON
      startTime = currentTime;
      break;


    case FSMStages::RUNNING:
      // Is the interval over?
      if (currentTime - startTime >= BLINK_ON_INTERVAL)
      {
        FSMChangeState(BlinkOff);
      }


      // Has the button been pressed?
      if (digitalRead(Button_IPPin) == LOW)
      {
        FSMChangeState(ButtonPressed);
      }
      break;


    case FSMStages::EXITING:
      break;
  }
}


void BlinkOff(enum FSMStages stage)
{
  static unsigned long startTime = 0;
  unsigned long currentTime = millis();
  switch (stage)
  {
    case FSMStages::ENTERING:
      Serial.println("Off");
      digitalWrite(LED_BUILTIN, LOW); // OFF
      startTime = currentTime;
      break;




    case FSMStages::RUNNING:
      // Is the interval over?
      if (currentTime - startTime >= BLINK_OFF_INTERVAL)
      {
        FSMChangeState(BlinkOn);
      }


      // Has the button been pressed?
      if (digitalRead(Button_IPPin) == LOW)
      {
        FSMChangeState(ButtonPressed);
      }
      break;




    case FSMStages::EXITING:
      break;
  }
}




void ButtonPressed(FSMStages stage)
{
  static unsigned long startTime = 0;
  unsigned long currentTime = millis();


  switch (stage)
  {
    case FSMStages::ENTERING:
      Serial.println("Pressed");
      digitalWrite(LED_BUILTIN, HIGH); // ON
      startTime = currentTime;
      break;


    case FSMStages::RUNNING:
      // Is the interval over?
      if (currentTime - startTime >= BUTTON_PRESSED_INTERVAL)
      {
        FSMChangeState(BlinkOff);
      }
      break;


    case FSMStages::EXITING:
      break;
  }
}


//
// Finite State Machine utility functions
//


void (*FSMCurrentState)(FSMStages stage);


void FSMRun()
{
  (*FSMCurrentState)(FSMStages::RUNNING);
}


// Enter a new state
void FSMEnterState(FSMStateFunction *SF)
{
  FSMCurrentState = SF;
  (*FSMCurrentState)(FSMStages::ENTERING);
}


// Exit current state
void FSMExitState()
{
  (*FSMCurrentState)(FSMStages::EXITING);
}


void FSMChangeState(FSMStateFunction *SF)
{
  FSMExitState();  // Exit current state
  FSMEnterState(SF);  // Enter a new state
}

ummm i didn't quite get you. Can we use a return() to get it to the very first statement?. i get it to sense the distance when i send a signal and then it stops detecting distance and keeps moving right, left or forwards. plz help me to fix this problem. it would be helpful if you tried it on my code and posted it so i can get a clear idea.

What are these loops for?

for(j=95;j<=180;j=j+1){
    myServo.write(j);
    delay(9);
  }

Why not just do

    myServo.write(180);

?

We usually don't have the hardware, software, nor time to test your code ourselves. The best we could do is probably try to compile the code.

The problem with your code I suspect are these while loops

while (myIR.decode(&cmd) == 0) { }

while loops are always tricky because they can easily "softlock" your entire program if you're careless. And no, you cannot use a return-to-top like function because when these while loops act up, it's trapped in there forever. No escape, no more instruction read.

This is my suspicion, but I think what happens in your program is this:

  1. Setup, and enter loop
  2. Print cmd.value
  3. Measure distance
  4. Re-print cmd.value
  5. While cmd is 0x000000, wait until cmd value IS NOT 0x000000
  6. cmd value changes, exit while.
  7. evaluate cmd, then set speed and direction to motor
  8. return to beginning of loop.
  9. print
  10. measure distance.
  11. re-print
  12. wait.
  13. wait.
  14. wait.
  15. did i mention the motor is still moving?
  16. wait.

i have to get rid of the problem of the motors still moving . that is the problem. what i want it to do is that when i press key 7 on the IR remote, it should do obstacle avoidance where it is supposed to move forward and stop when obstacle detected and then turn the servo right and left then it moves to the side with greater distance. it worked when i coded only obstacle avoidance and no ir remote. but i want multi function.so its still a problem. when i read the serial monitor, i can see that it measures the distance only once. but i need it to loop and check the distance again and again only when it is in the obstacle avoidance mode when i press key 7.

Here is a Finite State Machine that combines obstacle detection and IR commands. Perhaps you could use it as a starting point. It's slightly too long to post inline so it is attached.

IRCar.ino (9.37 KB)

a obstacle avoiding vehicle needs to do multiple things at the same time
first i want to describe the functionality in quite normal words

-measure distance to obstacles

  • receiving ir-remote commands and if one is received do different things depending on the command

  • switch drive-mode if obstacle comes near

so your code has to work this way

check if a ir-command was received
if not go on with next thing to do
if yes call related function

measure distance to obstacle

check for ir-cmd and measure distance must be executed all the time.

This means you have one singular big loop that calls functions all the time repeatedly.
This means function is entered does one single check and then function is left

if your vehicle shall drive to the right you set motors to drive right through a call of function drive_right
and LEAVE function drive_right well knowing that within the next 100 milliseconds your loop does
call all the functions again and again every 100 milliseconds or whatever your loop need time to run through one time

I don't know if the ir-receiver works based on interrupts if yes the receiving "in the backround" is no problem
the ultra-sonic sensors does a single meausuring and you store the distance in a variable

entering a function run through the function just checking is there something (an ir-code, a distance etc.) and leave the function as fast as possible well knowing that the next call of the function will be done in a short time

Is fundamentally different to multiple while loops.
Statemachines work this way

here is a link to an explanation The Finite State Machine | Majenko Technologies

best regards Stefan
best regards Stefan

Hi Mathew,

combining ultra-sonic sensors, and ir-remote commands takes the Arduino Uno near to his limits.
But I think it is doable.

I did some research which thing scould be done using interrupts in the backround.

drive the ultrasonic sensor in the backround I have found a demo-code

this demo-code uses the library TimerOne GitHub - PaulStoffregen/TimerOne: TimerOne Library with optimization and expanded hardware support

using this version enables measuring the distance every 50 milliseconds independently from other code-execution
and to read out the variable with the actual distance-value whenever needed.

As it uses timer1 the standard-servo-library can't be used because the standard-servo-library uses timer 1 too.

So I did some more research and found a library ServoTimer2 GitHub - nabontra/ServoTimer2: ServoTimer2 is a simple library for Arduino 1.x that does not use Timer1 in case of a conflict.
So this would bring together both isr-driven ultra-sonic sensor and driving servos

Now I have to analyse how the IR-remote-library works .... aha uses timer 2
so using timer 1 for the ultra-sonic sensors and timer 2 for servo is not possibe in combination with irRemote

hm .... I think the software-technique of creating a Ultra-sonic pulse and take a snapshot of micros() and then do a second snapshot of micros() when the echo rushes in could be done in a statemachine-loop too without using an timer-interrupt to send the pulse but using an interrupt attached to an IO-pin (isntead of a timer)

This means servos are driven by the standard-servo-library ir-remote is driven by timer 2
and measuring distance with the ultra-sonic sensor could be coded without interrupts.

I guess my post is somehow "above your head". No problem you can ask as many questions as you like
as long as you show some own effort in driving up the learning-curve of programming.

And this is a point where a standard Arduino comes near to his limits. maybe with an Arduino every is better suited in this application. IMHO the ESP32 is the better Arduino lots of PWM-pins 32 interrupts 4 64bit high-resolution timers much more RAM, more flash, flash can be used for storing files, WLAN and bluetooth on board all for half the price of a original arduino

best regards Stefan

StefanL38:
combining ultra-sonic sensors, and ir-remote commands takes the Arduino Uno near to his limits.
But I think it is doable.

It's certainly not a heavy burden on memory. :slight_smile:
The Finite State Machine implementation attached above uses 9% of PROGMEM and 21% of RAM on an Arduino UNO.

johnwasser:
It's certainly not a heavy burden on memory. :slight_smile:
The Finite State Machine implementation attached above uses 9% of PROGMEM and 21% of RAM on an Arduino UNO.

Not about memory but about timers
best regards Stefan

thankyou very much everyone but my current idea is to make a robot that does obstacle avoidance only when it gets this command and i want to exit that mode when i click on stop. so is there any way to make speed control default and then make the obstacle avoidance work when i press this? it is working but not checking the distance constantly. that is the problem. so if i could get a solution to that it would be helpful.

regards , Mathews

Hi Mathew,

having different modes like "no obstacle-avoiding" "obstacle-avoiding" fits perfectly to a statemachine.

The name describes it to the point: having different states that run through repeatedly and quick.
The repetetion enables do do multiple things at the same time (the real thing is execute code in sequence but with high speed so it looks like at the same time).

I will not analyse your existing code in detail or modify your posted code.

If you give a functional description in normal words. I emphasize in normal words what your robot shall do
I will write some code that shows how a statemachine works.

Making your existing code having two modes "no obstacle-avoiding" "obstacle-avoiding"
and making your code measuring distance to obstacles all the time without a statemachine

results in a hard to understand messy pile of if-conditions and boolean flags which will be hard to maintain.

Investing 1 to 2 hours in learning how statemachines work will offer a straight-forward easy to maintain
solution. A lot of parts of your existing code will be "recycled=re-used". But it is not done by adding 10 or 20 lines of code to your existing code.

best regards Stefan

hi Stefan thankyou for your response. What you told is correct but is there any way you could do the modification in the code. It is because i am a newbie to this.

It was easy to turn the object avoidance on and off: I just have the ReadDistance() function return "MaxDistance_CM" if you don't want to detect obstacles. :slight_smile:

Press the Forward button and the car will go forward until you press another button. Press the Object Avoid button and then the Forward button the car will go forward and turn to avoid obstacles.

IRCar2.ino (10.2 KB)

??? ??? THANKYOU SOOO MUCH !!! I GOT IT VERY USEFUL AND WAS AWESOME. I WOULD LOVE IT IF I KNEW WHAT IS FSM. EVERYTHING ELSE IS SPICK AND CLEAN. I UNDERSTOOD EVERYTHING.

MathewsJoby:
I WOULD LOVE IT IF I KNEW WHAT IS FSM.

In a "Finite State Machine" model, the sketch is always in one of a limited (finite) number of states. Each state does some stuff when you enter the state, looks for inputs and conditions that would trigger other states while in the state, and may do some clean-up when leaving the state. For the little set of utility functions I wrote, each state is represented by one function that looks like this:

void stateName(enum FSMStages stage)
{
  // The utility functions pass the 'stage' value to tell this function what to do.


  // Here is a good place to declare any 'static' (persistent) variables the state needs.
  static unsigned long startTime;


  switch (stage)
  {
    case FSMStages::ENTERING:
      // In the ENTERING stage we are switching from another state to this state.
      // Here we do whatever setup the state needs, sort of like the 'setup()' function
      // of the sketch.  For example, if the state had a timer, this would be a good
      // place to initialize the timer:
      startTime = millis();
      break;


    case FSMStages::RUNNING:
      // In the RUNNING stage we do nothing but look for inputs
      // that would move us to another state.

      // For example, we probably want to do something when the timer expires
      if (millis() - startTime > TimerInterval)
        FSM_ChangeState(TimerExpired);


      // There might also be a digital input of interest
      if (digitalRead(ButtonPin) == HIGH)
        FSM_ChangeState(ButtonPressed);


     // Each of those calls to FSM_ChangeState() will first call this (the current state's) function with
      // the argument 'FSMStages::EXITING' (see below) and then call the new state with the argument 
      // 'FSMStages::ENTERING'. 

      break;
    case FSMStages::EXITING:
      // In the EXITING state we do any clean-up we need.  In this case, none.
      break;
  }
}

typedef void (FSMStateFunction)(FSMStages stage);

What are you doing here? I've never run into this syntax before.

-jim lee

jimLee:

typedef void (FSMStateFunction)(FSMStages stage);

What are you doing here? I've never run into this syntax before.

The INTENT was to define a type to make it easier to declare a function that takes an argument of type "enum FSMStages" and returns 'void'. Unfortunately, it doesn't work for declaring state functions:

FSMStateFunction ObstacleDetected
{
  int rightDistance, leftDistance;
IIRCar2:154:3: error: expected primary-expression before 'int'
   int rightDistance, leftDistance;
   ^~~

I could not figure out how to get it to work for the intended purpose but I was able to use it to create POINTERS to such functions. That's all it's apparently good for.