2 кнопки нажаты одновременно, логика лифта

В настоящее время я создал работающий код лифта, в котором лифт поднимается при нажатии кнопки и останавливается на этаже, когда датчик определяет, что он достиг этажа. Вот как это работает:

#define Buzzer 5

#define pwmMot 6

#define halPin 8

#define butto1 9  //уровень 1
#define butto2 10 //уровень 2
#define butto3 11 //уровень 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); //остановка лифта
    digitalWrite(Buzzer, LOW);
    delay(100);
    digitalWrite(Buzzer, HIGH);
    required_level = -1;
  }
}

Теперь мне просто любопытно, как я могу расширить это, чтобы, например, если мы находимся на уровне 1, были нажаты уровни 2 и 3, он должен перейти на уровень 2, даже если сначала был нажат уровень 3. Или, если мы находимся на уровне 2 и нажаты оба уровня 1 и 3, он должен перейти к тому, который нажат первым, поскольку оба уровня находятся на одинаковом расстоянии от уровня 2.

, 👍0

Обсуждение

когда вы находитесь на 1 этаже, вы не можете просто прыгнуть на 3 этаж, вы должны сначала пройти уровень 2, если у вас там есть датчик, вы можете просто сделать что-то вроде if button2 = high && sensor2 = high {сделайте это} else ... я вижу в вашем будущем государственную машину!, @ElectronSurf

однозначно государственная машина, @chrisl

@newbie использует == вместо =, @Michel Keijzers

@MichelKeijzers верно, я просто демонстрировал..., @ElectronSurf

нет такой вещи как сценарий "две кнопки нажаты" применительно к микроконтроллеру... микроконтроллер проверяет кнопки последовательно... значит у вас один из двух сценариев, @jsotola


1 ответ


Лучший ответ:

3

если мы находимся на уровне 1, то нажаты уровни 2 и 3, должно пройти на уровень 2, даже если сначала был нажат уровень 3.

Чтобы это работало, программа должна помнить, какие кнопки (обратите внимание на множественное число!) были нажаты. Таким образом, вместо запоминания только одного запрос, как в

int required_level =-1;

у него должна быть логическая переменная для каждого из возможных уровней, сообщает нам, был ли запрошен стоп для этого уровня.

Для удобства я бы нумеровал уровни с нуля и держал их переменные в массиве:

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

если мы находимся на уровне 2 и нажаты оба уровня 1 и 3, он должен выйти к тому, который был нажат первым, поскольку оба уровня находятся на одном расстоянии со 2 уровня.

Та часть, которую я подчеркнул, не имеет для меня смысла. Лифт должен идти к тому, который был нажат первым, независимо от расстояния. Представьте, что вы находитесь в лифте на уровне 5, и нажмите кнопку для уровень 2. Как только лифт начинает движение вниз, другой пассажир нажимает кнопку для уровня 6. Если лифт немедленно вернется в движение вверх, чтобы достичь уровня 6, что ближе? Конечно, нет. Если это спускаясь вниз, он должен продолжать движение в этом направлении. Теперь, если другой Райдер нажимает 3, он должен остановиться на уровне 3 по пути вниз, даже если вы сначала нажали 2.

Как сказал Крисл в комментарии, конечный автомат определенно решение для такого рода проблем. Я предлагаю состояние машина с тремя состояниями: STOPPED, GOING_UP и GOING_DOWN:

  • когда ОСТАНОВЛЕНО, он должен измениться на GOING_UP или GOING_DOWN как можно скорее при нажатии кнопки перехода на другой уровень
  • когда GOING_UP, как только он достигает уровня, который был запрос, он должен измениться на STOPPED
  • то же самое, когда GOING_DOWN.

А вот предлагаемая мной реализация:

void loop() {
    // Проверяем кнопки.
    for (int i = 0; i < LEVEL_COUNT; i++)
        if (digitalRead(button[i]) == HIGH)
            requested_stop[i] = true;

    // Конечный автомат.
    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;
    }
}

В этом коде предполагается, что вы написали функцию elevator_height(), которая измеряет высоту лифта и определили массив константы LEVEL_HEIGHT[].

Обратите внимание, что это все еще далеко от совершенства. Вы, вероятно, должны убедиться что каждая остановка длится по крайней мере некоторую минимальную продолжительность. В противном случае, если лифт останавливается на уровне 1, в то время как уровень 0 также был запрошен, остановка продлится всего мгновение. Этого можно добиться, разделив Состояние STOPPED в двух разных состояниях и переключение с «ожидание всадникам входить/выходить» на «ожидание нажатия кнопки» на тайм-аут. Вы также можете убедиться, что после остановки лифт продолжать в том же направлении, если это возможно. Иначе никогда не будет достичь уровня 2, если какой-либо джокер неоднократно нажимает 0 и 1.

,

В лифте есть датчик и датчик на каждом уровне, поэтому вместо логики высоты уровня (у нас нет датчика, необходимого для измерения высоты уровня) мы не можем сказать, если датчик лифта соответствует датчику уровня и нажата кнопка, тогда остановитесь?, @Utsav

@Утсав: Да. Вам просто нужно заменить условие elevator_height() >= LEVEL_HEIGHT[current_level+1] на elevator_is_sensed_at_level(current_level+1). И аналогично для теста для current_level-1., @Edgar Bonet