States

Hi, working on a project. It`s a garage for a robot mower. I use two ultrasonic sensors to register distance from the mower to open/close garage door.
One sensor (distance_back) is inside og the garage and the other one (distance_front) is outside.

The problem Im having is that I use the stepper motor to open and close the garage. And if the mower is coming in and the distance is less than 15 cm to the distance_back sensor the door closes but then it should know that this is done. The problem is that when the code goes again the stepper motor will close the garage again even though its closed already. And the same problem with opens etc.

So I`ve made this:
bool front_less_than_30 =false;
bool front_more_than_30 =false;
bool back_more_than_15 =false;
bool back_less_than_15 =false;

And in the code set it to false/true but it dosen`t work.

I would be happy if anyone could help me out.

#include <Stepper.h>

const int Steps = 1000;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(Steps, 8, 9, 10, 11);

int led_green=6;
int led_red=7;

const int trigPin_front = 4; //Placed outside the house
const int echoPin_front = 5; //Placed outside the house

const int trigPin_back= 3;   //Placed inside the garage
const int echoPin_back= 2;   //Placed inside the garage

int inputVariable1_open=0;
int inputVariable_close=0;

bool front_less_than_30 =false;
bool front_more_than_30 =false;
bool back_more_than_15 =false;
bool back_less_than_15 =true;


float duration_front, distance_front;
float duration_back, distance_back;

void setup()
{
 pinMode(led_green, OUTPUT);
 pinMode(led_red, OUTPUT);
pinMode(trigPin_front, OUTPUT);
  pinMode(echoPin_front, INPUT);
  
 myStepper.setSpeed(60);
Serial.begin(9600);
}

void loop()
{
  //FRONT DISTANCE
 digitalWrite(trigPin_front, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin_front, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin_front, LOW);
  duration_front = pulseIn(echoPin_front, HIGH);
  distance_front = (duration_front*.0343)/2;
  delay(1000);


//BACK DISTANCE
 digitalWrite(trigPin_back, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin_back, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin_back, LOW);
  duration_back = pulseIn(echoPin_back, HIGH);
  distance_back = (duration_back*.0343)/2;
  delay(1000);

  Serial.println("Start");

if (distance_front<30 && front_less_than_30==true) //OPEN mower is outside coming in
{
  Serial.print("Open, mower coming inside, distance out is ");
  Serial.print(distance_front);
  Serial.print(", distance inside is ");
  Serial.println(distance_back);
  myStepper.step(Steps);
  delay(500);
   digitalWrite(led_green, HIGH);   
  delay(500);                       
  digitalWrite(led_green, LOW);    
  delay(500);    
   front_less_than_30  =false;
    front_more_than_30 =true; 
    back_more_than_15  =true;
    back_less_than_15  =true;
   
}
else if (distance_front>30 && front_more_than_30 ==true) //CLOSE mower is outside
{

 Serial.print("Close, mower is out mowing, distance out is ");
  Serial.print(distance_front);
  Serial.print(" distance inside is ");
  Serial.println(distance_back);
  myStepper.step(-Steps);
  delay(500);
   digitalWrite(led_red, HIGH);  
  delay(500);                       
  digitalWrite(led_red, LOW);   
  delay(500);    
  front_more_than_30 =false; 
  front_less_than_30 =true;
  back_more_than_15  =true;
  back_less_than_15  =true;
  
}
else if (distance_back>15 && back_more_than_15 ==true) //OPEN mower driving out
{

 Serial.print("Open, mower drives out, distance inside is");
  Serial.print(distance_back);
  Serial.print(" distanse out is ");
  Serial.println(distance_front);
  myStepper.step(Steps);
  delay(500);
   digitalWrite(led_green, HIGH);  
  delay(500);                     
  digitalWrite(led_green, LOW);    
  delay(500);     
  back_more_than_15  =false;
  back_less_than_15  =true;
  front_more_than_30 =true; 
  front_less_than_30 =true;
}
else if (distance_back<15 && back_less_than_15 ==true) //CLOSE mower is parked
{

  Serial.print("Close, mower is parked, distance inside is");
  Serial.print(distance_back);
  Serial.print(" distance outside is ");
  Serial.println(distance_front);
  myStepper.step(-Steps);
  delay(500);
   digitalWrite(led_red, HIGH);   
  delay(500);                      
  digitalWrite(led_red, LOW);  
  delay(500);     
  back_less_than_15  =false;
  front_more_than_30 =true; 
  front_less_than_30 =true;
  back_more_than_15  =true;

}

}

Your states should be things like “door closed”, “door opening”, “door open”, etc for the door.
And perhaps also “mower outside”, “mower coming in”, “mower inside”, etc for the mower.

Such a states are not really suitable for a boolean. A boolean can only hold 2 states, and (at least in the above model) each has more than 2 possible states.

I’m not sure what having your states named exactly after the conditions they are testing for is about…

if (distance_front<30 && front_less_than_30==true) //OPEN mower is outside coming in

Perhaps you understood what this is meant to do, but it made zero sense to me - sorry.

Something like this is more what I would expect to see…

if (distance_front<30 && mower_state == OUTSIDE) //OPEN mower is outside coming in
{
  // Open the door
  door_state = OPEN;
  mower_state = MOVING_IN;
}
if (distance_back<15 && door_state == OPEN) //CLOSE mower is parked
{
  // Close the door
  door_state = CLOSED;
  mower_state = INSIDE;
}

I was also perplexed by your approach. It's rare, but not unheard of, to capture comparisons in a variable like you have. However here, I don't see the reason. It's your program so it's "on your dime", but at least you should not have two variables to store one value:

bool front_less_than_30 =false;
bool front_more_than_30 =false;

In some imaginary case where it is important to note when "front_equal_to_30", this might make sense. But you are just comparing distances. Excluding equality, if something is not less than 30, it is more than 30 and if it is more than 30, it is not less than 30. So it is confusing and error prone to maintain dual variables. If they both get set to 'true' you have a logical contradiction, so an error. Each one must be set, each time... and which one do you test?

I recommend getting rid of these variables entirely, and just testing the distances and taking appropriate actions according to that instead. There is no reason not to consider something either less than, or else equal to or greater than, a fixed distance.

Your sequence of events should be controlled by state logic, as suggested in the previous post.

pcbbc:
Something like this is more what I would expect to see...

Your example does not show the OP how to use an ENUM to create the states such as MOVING_IN

...R

consider

Mover Door
 dist   5, distLst   0, door Closed, mover Leaving
Opening
 dist  10, distLst   5, door Opening, mover Leaving
Open
 dist  15, distLst  10, door Open, mover Leaving
Closing
 dist  20, distLst  15, door Closing, mover Leaving
Closed
 dist  25, distLst  20, door Closed, mover Leaving
 dist  20, distLst  25, door Closed, mover Approaching
 dist  15, distLst  20, door Closed, mover Approaching
Opening
Open
 dist  10, distLst  15, door Open, mover Approaching
 dist   5, distLst  10, door Open, mover Approaching
 dist   0, distLst   5, door Open, mover Approaching
Closing
Closed
 dist   5, distLst   0, door Closed, mover Leaving
Opening
Open
#include <Stepper.h>

#define Led1Pin     10
#define Led2Pin     11

byte butPins [] = { A1, A2, A3 };
#define N_BUTS  sizeof(butPins)

byte but     [N_BUTS];
byte butLst  [N_BUTS];

#define Steps 1000
Stepper myStepper(Steps, 5, 6, 7, 8);   // unused

static int  dist     = 0;
static int  distLst  = 0;

enum { Stopped, Leaving, Approaching };
const char * mowerStr [] = {"Stopped", "Leaving", "Approaching" };
static int mower = Stopped;

const char* doorStr [] = { "Closed", "Opening", "Open", "Closing" };
enum { Closed, Opening, Open, Closing };
static int door = Closed;

#define Cnt   25
int  cnt = 0;
char s [80];

// -----------------------------------------------------------------------------
void ledToggle (byte pin) { digitalWrite (pin, ! digitalRead (pin)); }
void ledOn     (byte pin) { digitalWrite (pin, LOW); }
void ledOff    (byte pin) { digitalWrite (pin, HIGH); }

// -----------------------------------------------------------------------------
void loop()
{
    // capture previous dist
    distLst = dist;

    // update dist
    for (unsigned n = 0; n < N_BUTS; n++)  {
        byte but = digitalRead (butPins [n]);

        if (butLst [n] != but)  {
            butLst [n] = but;

            sprintf (s, " but %d [%d] change", n, butPins [n]);
        //  Serial.println (s);

            if (LOW == but) {   // button pressed  
                switch (butPins [n])  {
                case A1:
                    dist -= 5;
                    dist  = 0 > dist ? 0 : dist;
                    break;

                case A2:
                    dist += 5;
                    break;

                default:
                    break;
                }
                delay (10);         // debounce
            }
        }
    }

    // determine mower state: direction or stopped
    if (dist == distLst)
        mower = Stopped;
    else  {
        if (dist > distLst)
            mower = Leaving;
        else if (dist < distLst)
            mower = Approaching;
    
        sprintf (s, " dist %3d, distLst %3d, door %s, mover %s",
                    dist, distLst, doorStr [door], mowerStr [mower]);
        Serial.println (s);
    }

    // determine action based on door and mower state
    switch (door)  {
    case Closed:
        if (   (10 > dist && Leaving == mower)
            || (20 > dist && Approaching == mower) ) {
            door = Opening;
            Serial.println ("Opening");
            ledOff (Led1Pin);
            cnt = Cnt;
        }
        break;

    case Opening:
        if (0 == cnt--)  {
            door = Open;
            Serial.println ("Open");
            ledOn (Led2Pin);
        }
        else
            ledToggle (Led2Pin);
        break;

    case Open:
        if (   (10 < dist && Leaving == mower)
            || (0 == dist && Approaching == mower) )  {
            door = Closing;
            Serial.println ("Closing");
            ledOff (Led2Pin);
            cnt = Cnt;
        }
        break;

    case Closing:
        if (0 == cnt--) {
            ledOn  (Led1Pin);
            door = Closed;
            Serial.println ("Closed");
        }
        else
            ledToggle (Led1Pin);
        break;
    }

    delay (100);
}

// -----------------------------------------------------------------------------
void setup()
{
    Serial.begin(9600);
    Serial.println("Mover Door");

    pinMode (Led1Pin, OUTPUT);
    pinMode (Led2Pin, OUTPUT);

    ledOn  (Led1Pin);
    ledOff (Led2Pin);

#if 0
    pinMode(trigPin_front, OUTPUT);
    pinMode(echoPin_front, INPUT);
    myStepper.setSpeed(60);
#endif

    for (unsigned n = 0; n < N_BUTS; n++)  {
        pinMode (butPins [n], INPUT_PULLUP);
        butLst [n] = digitalRead (butPins [n]);
    }
}

Hi Arduinofan,

you should do an analysis what are the measured distcances for the following situations:

mower far away 
back------------------------------front-------------------------------------------mower



Mower comes in
back|                              front<---30cm----->|mower
    |<------------?? cm------------------------------>|
    

    
Mower is below frontsensor
back|                             front<---?? cm-------------------->
    |                            |mower
    |<-----------?? cm---------->|


    
    
Mower is at parkposition
back|                             front<---?? cm-------------------->
    |               |mower
    |<--?? cm------>|

analyse what measurings do you really get while the mower is driving in / driving out
add serial output to your code that prints out the measured distance all the time

you can reduce the number of lines printed with a non-blocking timer

unsigned long MyTimer = 0; 

boolean TimePeriodIsOver (unsigned long &expireTime, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - expireTime >= TimePeriod )
  {
    expireTime = currentMillis; // set new expireTime
    return true;                // more time than TimePeriod) has elapsed since last time if-condition was true
  } 
  else return false;            // not expired
}

and inside your loop()

  if (  TimePeriodIsOver(MyTimer,500)  ) // print only every 0,5 seconds
    {
      Serial.print("distance out is ");
      Serial.print(distance_front);
      Serial.print(" distance inside is ");
      Serial.println(distance_back);
    }

as an additional indicator what is happening you can determine if mower is driving in or driving out
through storing two distances from back-sensor with a well chosen interval of time. not too short not too long.

by using a second timer-variable

every time the well chosen period is over
set
older distance_back = newer distance_back ;
newer distance_back = distance_back;

example numbers

older distance_back is 48
newer distance_back is 41

distance_back reaches 35 after measuring-period

so
older distance_back = newer distance_back ;
was 48 becomes 41

newer distance_back = distance_back;
was 41 becomes 35

etc. etc.

If older_distance > newer_distance ==> mower is driving it

If older_distance < newer_distance ==> mower is driving out

and you should check if the measurings are influenced through the opening/closing door

best regards Stefan

Thank you everyone.
Some of it was a little to difficult, but i think I might try to use the methood pcbbc explained to me.

One thing, what would I have to decalre door_state and mower_state as before the void_setup?

Thank you very much

Now I have this:

#include <Stepper.h>

const int Steps = 1000;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(Steps, 8, 9, 10, 11);

int led_green=6;
int led_red=7;

const int trigPin_front = 4; //Placed outside the garage
const int echoPin_front = 5; //Placed outside the garage

const int trigPin_back= 3;   //Placed inside the garage
const int echoPin_back= 2;   //Placed inside the garage

int inputVariable1_open=0;
int inputVariable_close=0;



float duration_front, distance_front;
float duration_back, distance_back;

void setup()
{
 pinMode(led_green, OUTPUT);
 pinMode(led_red, OUTPUT);
pinMode(trigPin_front, OUTPUT);
  pinMode(echoPin_front, INPUT);
  
 myStepper.setSpeed(60);
Serial.begin(9600);
}

void loop()
{
  //FRONT DISTANCE
 digitalWrite(trigPin_front, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin_front, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin_front, LOW);
  duration_front = pulseIn(echoPin_front, HIGH);
  distance_front = (duration_front*.0343)/2;
  delay(1000);


//BACK DISTANCE
 digitalWrite(trigPin_back, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin_back, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin_back, LOW);
  duration_back = pulseIn(echoPin_back, HIGH);
  distance_back = (duration_back*.0343)/2;
  delay(1000);

  Serial.println("Starter");




if (distance_front<30 && mower_state == OUTSIDE) //OPEN mower is outside coming in
{
  // Open the door
  door_state = OPEN;
  mower_state = MOVING_IN;
  Serial.print("Open, mower is on it`s way in, distance front is ");
  Serial.print(distance_front);
  Serial.print(", distanse inside is ");
  Serial.println(distance_back);
  myStepper.step(Steps);
  delay(500);
   digitalWrite(led_green, HIGH);
  delay(500);                
  digitalWrite(led_green, LOW);  
  delay(500);    
  
  
}
if (distance_back<15 && door_state == OPEN) //CLOSE mower is parked
{
  // Close the door
  door_state = CLOSED;
  mower_state = INSIDE;
   Serial.print("Close, mower is parked, ditance inside is ");
  Serial.print(distance_back);
  Serial.print(" distanse out is ");
  Serial.println(distance_front);
  myStepper.step(-Steps);
  delay(500);
   digitalWrite(led_red, HIGH);  
  delay(500);                      
  digitalWrite(led_red, LOW);  
  delay(500);     
}


 
}
else if (distance_front>30) //CLOSE mower is out mowing
{
 Serial.print("Close, mower is outside mowing, distance front is ");
  Serial.print(distance_front);
  Serial.print(" distanse inside is ");
  Serial.println(distance_back);
  myStepper.step(-Steps);
  delay(500);
   digitalWrite(led_red, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(led_red, LOW);    // turn the LED off by making the voltage LOW
  delay(500);    

  
}
else if (distance_back>15) //OPEN mower is going out
{

 Serial.print("Open, mower is going out, distance inside is ");
  Serial.print(distance_back);
  Serial.print(" distanse out is ");
  Serial.println(distance_front);
  myStepper.step(Steps);
  delay(500);
   digitalWrite(led_green, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(led_green, LOW);    // turn the LED off by making the voltage LOW
  delay(500);     
 
}




}

arduinofan90:
One thing, what would I have to declare door_state and mower_state as before the void_setup?

I’d use the sensors to determine if the mower is present and where.
The door state is a little tricky, as you don’t seem to have a sensor for that?
Really you should have end stop sensors and not rely on a fixed number of steps to open/close.

Surely...

else if (distance_front>30 && door_state == OPEN)
{
  // Close the door
  door_state = CLOSED;
}

And similarly you'll need to fix...

else if (distance_back>15) //OPEN mower is going out

Basically: Do not change to a new state (open or close the door) without:
a) Checking the current state is correct
b) Updating the state when you are done

Aha, I can just have one more ultrasonic sensor attatched to the garage door facing down to measure the distance height from the garagedor to the surface and then have like:

if sensor_out<15 && sensor_facing_down <2 //Mower is coming up to garage door and entering

( Open door)

if sensor_out >15 && sensor_inside<5 //Mower is inside parked

(close door)

and so on…

I`ll try this when I come home.

#include <Stepper.h>

const int Steps = 1000;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(Steps, 8, 9, 10, 11);

int led_green=6;
int led_red=7;

const int trigPin_front = 4; //Placed outside the garage
const int echoPin_front = 5; //Placed outside the garage

const int trigPin_back= 3;   //Placed inside the garage
const int echoPin_back= 2;   //Placed inside the garage

const int trigPin_on_garage= 12;   //Placed inside the garage
const int echoPin_on_garage= 13;   //Placed inside the garage


float duration_on_garage, distance_on_garage;
float duration_front, distance_front;
float duration_back, distance_back;

void setup()
{
 pinMode(led_green, OUTPUT);
 pinMode(led_red, OUTPUT);
pinMode(trigPin_front, OUTPUT);
  pinMode(echoPin_front, INPUT);
  
 myStepper.setSpeed(60);
Serial.begin(9600);
}

void loop()
{
  //FRONT DISTANCE
 digitalWrite(trigPin_front, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin_front, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin_front, LOW);
  duration_front = pulseIn(echoPin_front, HIGH);
  distance_front = (duration_front*.0343)/2;
  delay(1000);


//BACK DISTANCE
 digitalWrite(trigPin_back, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin_back, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin_back, LOW);
  duration_back = pulseIn(echoPin_back, HIGH);
  distance_back = (duration_back*.0343)/2;
  delay(1000);

  Serial.println("Starter");




if (distance_back < 5 && distance_on_garage > 3) //Mower is parked, garage= closed
{
  Serial.print("Door is closed mower is docked, distance inside is ");
  Serial.print(distance_back);
  Serial.print(", distanse garagedoor is  ");
  Serial.println(distance_on_garage);
  myStepper.step(Steps);
  delay(500);
   digitalWrite(led_green, HIGH);
  delay(500);                
  digitalWrite(led_green, LOW);  
  delay(500);    
    
}
else if (distance_back > 5 && distance_on_garage < 3) //Mower is leaving dock= Open
{
   Serial.print("Mower is leaving dock for mowing, distance back is ");
  Serial.print(distance_back);
  Serial.print(" distanse garagedoor is ");
  Serial.println(distance_on_garage);
  myStepper.step(-Steps);
  delay(500);
   digitalWrite(led_red, HIGH);  
  delay(500);                      
  digitalWrite(led_red, LOW);  
  delay(500);     
}
 
else if (distance_back > 15 && distance_on_garage > 3) //Mower is out mowing= Closed
{
 Serial.print("Mower is outside mowing, distance back is ");
  Serial.print(distance_back);
  Serial.print(" distanse garagedoor is ");
  Serial.println(distance_on_garage);
  myStepper.step(Steps);
  delay(500);
   digitalWrite(led_red, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(led_red, LOW);    // turn the LED off by making the voltage LOW
  delay(500);    

  
}
else if (distance_front < 40 && distance_on_garage < 3) //Mower is coming in docking = Open
{

 Serial.print("Mower is docking, distance outside is ");
  Serial.print(distance_front);
  Serial.print(" distanse garagedoor is ");
  Serial.println(distance_on_garage);
  myStepper.step(-Steps);
  delay(500);
   digitalWrite(led_green, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(led_green, LOW);    // turn the LED off by making the voltage LOW
  delay(500);     
 
}

}