0

I have currently created a working elevator code where the elevator goes up when pressed a button, and stops at a floor when the sensor senses that it has reached the floor. This is how it works:

#define Buzzer 5

#define pwmMot 6

#define halPin 8

#define butto1 9  //level 1
#define butto2 10 //level 2
#define butto3 11 //level 3

#define SeEcho 12
#define SeTrig 13

int button1_status = 0;
int button2_status = 0;
int button3_status = 0;

int current_level = 1;
int required_level =-1;

void setup(){
  Serial.begin(9600);
  pinMode(Buzzer, OUTPUT);
  digitalWrite(Buzzer, HIGH);
  pinMode(halPin, INPUT);
  pinMode(butto1, INPUT);
  pinMode(butto2, INPUT);
  pinMode(butto3, INPUT);
  pinMode(SeTrig, OUTPUT);
  pinMode(SeEcho, INPUT);
  pinMode(pwmMot, OUTPUT);
  Serial.println("you are in level 1");
}

void emergencyStop(){
  analogWrite(pwmMot, 255);
}
int sensor() {
  unsigned long duration;
  int distance;
  digitalWrite(SeTrig, LOW);
  delayMicroseconds(2);
  digitalWrite(SeTrig, HIGH);
  delayMicroseconds(5);
  digitalWrite(SeTrig,LOW);
  duration = pulseIn(SeEcho,HIGH);  
  distance = int(duration/2/29.412);
  return distance;
}

bool hallSen(){
  return digitalRead(halPin);
}

int going_up(){
  while (sensor() > 12){
    analogWrite(pwmMot, 1600);
  }
  return 1;
}

int going_down(){
  while (sensor() > 12){
    analogWrite(pwmMot, 570);
  }
  return 1;
}

void loop() {
  button1_status = digitalRead(butto1);
  button2_status = digitalRead(butto2);
  button3_status = digitalRead(butto3);
  required_level = button1_status == HIGH ? 1 : button2_status == HIGH ? 2 : button3_status == HIGH ? 3 : -1;
  if (required_level != -1 && required_level != current_level){
    while (current_level != required_level){
      if (current_level > required_level) Serial.println("Going Down"), current_level-=going_down();
      else if (current_level< required_level) Serial.println("Going Up"), current_level+=going_up();
      Serial.print("you are in level "); Serial.println(current_level);
      delay(1000);
    }
    analogWrite(pwmMot, 1550); //stop elevator
    digitalWrite(Buzzer, LOW);
    delay(100);
    digitalWrite(Buzzer, HIGH);
    required_level = -1;
  }
}

Now I am just curious as to how I will extend this so that for example if we are in level 1, both the levels 2 and 3 are pressed it should go to level 2 even if level 3 was pressed first. Or if we are in level 2 and both level 1 and 3 are pressed, it should go to the one that is pressed first as both levels are the same distance from level 2.

  • when you are at floor 1 you can't just jump to floor 3 you have to pass level 2 first, if you have a sensor there you can simply do something like if button2 = high && sensor2 = high {do that} else... i see a state machine in your future! – Hamed Sep 3 at 7:07
  • definitely a state machine – chrisl Sep 3 at 7:08
  • @newbie use == instead of = – Michel Keijzers Sep 3 at 7:59
  • 1
    @MichelKeijzers right, i was just demonstrating... – Hamed Sep 3 at 8:21
  • there is no such thing as a "two buttons pressed" scenario as far as the microcontroller is concerned ... the microcontroller checks the buttons sequentially ... that means you have one of two scenarios – jsotola Sep 3 at 17:24
2

if we are in level 1, both the levels 2 and 3 are pressed it should go to level 2 even if level 3 was pressed first.

For this to work, the program should remember which buttons (mind the plural!) have been pressed. Thus, instead of remembering only one request, as in

int required_level =-1;

it should have a boolean variable for each of the possible levels, telling us whether a stop was requested for that level.

For convenience, I would number the levels from zero, and hold these variables in an array:

const int LEVEL_COUNT = 3;
bool requested_stop[LEVEL_COUNT];

if we are in level 2 and both level 1 and 3 are pressed, it should go to the one that is pressed first as both levels are the same distance from level 2.

The part I emphasized doesn't make sense to me. The elevator should go to the one that was pressed first, irrespective of the distances. Imagine you are in an elevator at level 5, and press the button for level 2. As the elevator just starts moving down, another rider presses the button for level 6. Should the elevator immediately revert to going up in order to reach level 6, which is closer? Of course not. If it is going down, it should continue in that direction. Now, if the other rider presses 3, it should stop by level 3 on its way down, even though you pressed 2 first.

As stated by chrisl in a comment, a finite state machine is definitely the solution for this kind of problems. I propose a state machine with three states, STOPPED, GOING_UP, and GOING_DOWN:

  • when STOPPED, it should change to GOING_UP or GOING_DOWN as soon as a button for another level is pressed
  • when GOING_UP, as soon as it reaches a level that has been requested, it should change to STOPPED
  • same thing when GOING_DOWN.

And here is my proposed implementation:

void loop() {
    // Check the buttons.
    for (int i = 0; i < LEVEL_COUNT; i++)
        if (digitalRead(button[i]) == HIGH)
            requested_stop[i] = true;

    // Finite state machine.
    static enum { STOPPED, GOING_UP, GOING_DOWN } state = STOPPED;
    switch (state) {
    case STOPPED:
        requested_stop[current_level] = false;
        for (int i = 0; i < LEVEL_COUNT; i++) {
            if (requested_stop[i]) {
                if (i < current_level) {
                    analogWrite(pwmMot, PWM_DOWN);
                    state = GOING_DOWN;
                    break;
                } else if (i > current_level) {
                    analogWrite(pwmMot, PWM_UP);
                    state = GOING_UP;
                    break;
                }
            }
        }
        break;
    case GOING_UP:
        if (elevator_height() >= LEVEL_HEIGHT[current_level + 1]) {
            current_level++;
            if (requested_stop[current_level]) {
                analogWrite(pwmMot, PWM_STOP);
                state = STOPPED;
            }
        }
        break;
    case GOING_DOWN:
        if (elevator_height() <= LEVEL_HEIGHT[current_level - 1]) {
            current_level--;
            if (requested_stop[current_level]) {
                analogWrite(pwmMot, PWM_STOP);
                state = STOPPED;
            }
        }
        break;
    }
}

This code assumes you have written the function elevator_height() that measures the height of the elevator, and have defined an array of constants LEVEL_HEIGHT[].

Notice that this is still far from perfect. You should probably ensure that each stop lasts at least some minimum duration. Otherwise, if the elevator stops at level 1 while level 0 has also been requested, the stop will only last an instant. This can be achieved by splitting the STOPPED state in two distinct states, and switching from “waiting for the riders to go in/out” to “waiting for a button to be pressed” on a timeout. You may also want to ensure that, after a stop, the elevator continues in the same direction if possible. Otherwise it will never reach level 2 if some joker is repeatedly pressing 0 and 1.

  • There is a sensor in the elevator and a sensor in each level so instead of the level height logic (we dont have the required sensor to measure the level height) cant we say if elevator sensor matches level sensor and button pressed there then stop? – Utsav Sep 10 at 4:52
  • @Utsav: Yes. You would just have to replace the condition elevator_height() >= LEVEL_HEIGHT[current_level+1] by elevator_is_sensed_at_level(current_level+1). And similarly for the test for current_level-1. – Edgar Bonet Sep 10 at 7:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.